Я пытаюсь смоделировать условия гонки при записи в файл. Это то, что я делаю.
Однако запись process1 записывается в конец файла, и между процессами нет конфликтов записи.
Я использую fopen как fopen("./a.txt", "a+)
Может кто-нибудь сказать, почему это поведение и как я могу имитировать состояние гонки при записи в файл?
Код процесса1:
#include <iostream>
#include <fstream>
#include <string>
#include <stdio.h>
#include "time.h"using namespace std;
int main()
{
FILE *f1= fopen("./a.txt","a+");
cout<<"opened file1"<<endl;
string data ("hello world");
fwrite(data.c_str(), sizeof(char), data.size(), f1);
fflush(f1);
cout<<"file1 tell "<<ftell(f1)<<endl;
cout<<"wrote file1"<<endl;
sleep(3);
string data1 ("bye world");;
cout<<"wrote file1 end"<<endl;
cout<<"file1 2nd tell "<<ftell(f1)<<endl;
fwrite(data1.c_str(), sizeof(char), data1.size(), f1);
cout<<"file1 2nd tell "<<ftell(f1)<<endl;
fflush(f1);
return 0;
}
В процессе2 я закомментировал sleep
заявление.
Я использую следующий скрипт для запуска:
./process1 &
sleep 2
./process2 &
Спасибо за ваше время.
Код писателя:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BLOCKSIZE 1000000
int main(int argc, char **argv)
{
FILE *f = fopen("a.txt", "a+");
char *block = malloc(BLOCKSIZE);
if (argc < 2)
{
fprintf(stderr, "need argument\n");
}
memset(block, argv[1][0], BLOCKSIZE);
for(int i = 0; i < 3000; i++)
{
fwrite(block, sizeof(char), BLOCKSIZE, f);
}
fclose(f);
}
Функция читателя:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BLOCKSIZE 1000000
int main(int argc, char **argv)
{
FILE *f = fopen("a.txt", "r");
int c;
int oldc = 0;
int rl = 0;
while((c = fgetc(f)) != EOF)
{
if (c != oldc)
{
if (rl)
{
printf("Got %d of %c\n", rl, oldc);
}
oldc = c;
rl = 0;
}
rl++;
}
fclose(f);
}
Я побежал ./writefile A & ./writefile B
затем ./readfile
Я получил это:
Got 1000999424 of A
Got 999424 of B
Got 999424 of A
Got 4096 of B
Got 4096 of A
Got 995328 of B
Got 995328 of A
Got 4096 of B
Got 4096 of A
Got 995328 of B
Got 995328 of A
Got 4096 of B
Got 4096 of A
Got 995328 of B
Got 995328 of A
Got 4096 of B
Got 4096 of A
Got 995328 of B
Got 995328 of A
Got 4096 of B
Got 4096 of A
Got 995328 of B
Got 995328 of A
Как вы можете видеть, есть хорошие длинные серии A и B, но они не точно 1000000 символов, что соответствует размеру, который я им написал. Весь файл после пробного запуска с меньшим размером при первом запуске составляет всего 7 ГБ.
Для справки: Fedora Core 16 с моим собственным скомпилированным ядром 3.7rc5, gcc 4.6.3, x86-64 и ext4 поверх lvm, четырехъядерный процессор AMD PhenomII, 16 ГБ ОЗУ
Запись в режиме добавления является атомарной операцией. Вот почему это не сломалось.
Теперь … как это сломать?
Попробуйте отобразить файл в памяти и записать в память два процесса. Я уверен, что это сломает это.
Я почти уверен, что вы не можете положиться на такое поведение, но оно вполне может работать надежно в некоторых системах. Запись в один и тот же файл из двух разных процессов, скорее всего, рано или поздно вызовет проблемы, если вы «постараетесь». И закон Сода гласит, что именно тогда ваш начальник проверяет, работает ли программное обеспечение, когда ваш заказчик доставляет проданную вами систему, или когда вы завершаете подготовку своего отчета, на создание которого ушли годы, или какое-то другое важное время.
Поведение, которое вы пытаетесь сломать или увидеть, зависит от того, с какой ОС вы работаете, поскольку запись в файл является системным вызовом.
На том, что вы сказали нам о первом дескрипторе файла, чтобы он не переписывал то, что написал второй процесс, тот факт, что вы открыли файл в режиме добавления в обоих процессах, возможно, актуализировал значение ftell перед тем, как фактически записать его.
Вы пытались сделать то же самое со стандартными функциями открытия и записи? Это может быть интересно.
РЕДАКТИРОВАТЬ: Справочный документ C ++ объясняет о опции добавления fopen Вот:
«append / update: открыть файл для обновления (как для ввода, так и для вывода) со всеми операциями вывода, записывающими данные в конец файла. Операции перемещения (fseek, fsetpos, rewind) влияют на следующие операции ввода, но операции вывода перемещают позиционировать обратно в конец файла. «Это объясняет поведение, которое вы наблюдали.