Я обнаружил, что открытый файловый поток испортится, если мы сделаем fork () перед его закрытием.Хорошо известно, что параллелизм, то есть условия гонки, могут возникать, когда родительский и дочерний процессы хотят изменить файловый поток.Тем не менее, даже когда дочерний процесс никогда не касается файлового потока, он по-прежнему имеет неопределенное поведение.Мне было интересно, может ли кто-нибудь объяснить это, возможно, из-за того, как ядро работает с файловым потоком на этапах, когда дочерний процесс разветвляется и завершается.
Ниже приведен небольшой фрагмент странного поведения:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
// Open file
FILE* fp = fopen("test.txt", "r");
int count = 0;
char* buffer = NULL;
size_t capacity = 0;
ssize_t line = 0;
while ( (line = getline(&buffer, &capacity, fp)) != -1 ) {
if (line > 0 && buffer[line - 1] == '\n') // remove the end '\n'
buffer[line - 1] = 0;
pid_t pid = fork();
if (pid == 0) {
// fclose(fp); // Magic line here: when you add this, everything is fine
if (*buffer == '2')
execlp("xyz", "xyz", NULL);
else
execlp("pwd", "pwd", NULL);
exit(1);
} else {
waitpid(pid, NULL, 0);
}
count++;
}
printf("Loops: %d\n", count);
return 0;
}
Просто скопируйте код в новый файл (например, test.c).И создайте .txt файл test.txt с простым содержимым
1
2
3
4
и запустите
$ gcc test.c && ./a.out
. В файле 4 строки.Ожидается, что циклы прочитают каждую строку и выполнятся ровно 4 раза (1 2 3 4).И я решил позволить ему выполнить недопустимую команду "xyz", когда он находится во 2-м цикле.Затем вы обнаружите, что цикл фактически выполняется 6 раз (1 2 3 4 3 4)!Дело в том, что, когда все четыре выполненные команды являются действительными, ничто не пойдет не так.Но если выполняется недопустимая команда, каждая команда после нее будет выполнена дважды.(Обратите внимание, что это странное поведение возникает только на Linux-машине, с моей Mac OS все в порядке, не уверен насчет Windows. Так что проблема зависит от платформы?)
Похоже, что когда я выполняю fork (),Поток файла в parent больше не обещает быть старым fp (недетерминированное поведение), даже когда мой дочерний процесс его не трогает.
Временное решение, которое я нашел, это: fclose (fp) в дочернем процессе,Это заставит замолчать вышеупомянутое странное поведение, но в более сложных условиях могут наблюдаться и другие вещи.Было бы полезно, если бы кто-нибудь дал мне некоторое представление об этой проблеме.Спасибо