Неожиданный EOF при чтении файла в многопроцессорной среде
У меня есть файл instructions.txt
(обозначается указателем файла fp
) который состоит из 12 строк (каждая строка содержит байты ls\n
а также ps\n
в качестве альтернативы).
Первоначально основной процесс открывает файл в режиме чтения, создает и инициализирует общую область памяти. mem
и создает еще 11 процессов, используя fork()
,
Предполагается, что каждый из 12 процессов читает только одну строку из файла и выполняет эту инструкцию. Прежде чем войти в крайнее while
блокировать, вызывая ftell(fp)
во всех процессах возвращает 0.
Проблема в том, что после первого процесса, который входит в самый внешний if
блок читает одну строку, используя fgets
звонит ftell
в других процессах возвращает 36 (размер файла 12x3 = 36 байт). ftell
в процессе, который выполнил fgets
first по-прежнему возвращает 3 (конец первой строки).
Так что в следующий раз любой процесс вызывает fgets
, он возвращает EOF
Область общей памяти mem
используется в качестве "массива", где элементы с 1-го по 12-й содержат PID 12 процессов, а 0-й элемент используется в качестве индекса, чтобы определить, какой процесс войдет во внешний if
блок.
Вот фрагмент кода, который вызывает проблему -
while(mem[0] > 0)
{
printf("(%u) pos = %ld\n", curr_pid, ftell(fp));
// only the process whose PID matches the value in
// mem[mem[0]] can enter
if(curr_pid == mem[mem[0]])
{
printf("\n\nprocess %u enters CS\n", curr_pid);
char instr[100];
printf("pos before read = %ld\n", ftell(fp));
if(fgets(instr, 100, fp) == NULL)
{
perror("fgets error or EOF");
//return 1;
}
printf("pos after read = %ld\n", ftell(fp));
instr[strlen(instr)-1] = 0;
printf("process %u executing command: %s, size = %lu\n", curr_pid, instr, strlen(instr));
/* execute instruction */
char *args[] = {instr, NULL};
pid_t exec_pid = fork();
if(exec_pid == -1)
{
perror("fork error");
}
else if(exec_pid == 0) // child execs
{
execvp(instr, args);
perror("execvp error");
return 1;
}
printf("process %u leaving CS\n", curr_pid);
sleep(5);
mem[0]--; // alow next process to enter and read
}
sleep(1);
}
Вот
(FILE *) fp
указатель файла наinstructions.txt
файл(int *) mem
является общей памятью, прикрепленной ко всем 12 процессамmem[0]
это индекс (значения от 1 до 12 включительно), по которому PID для процесса, который будет выбран для вводаif
блок найден вmem
(То есть,mem[mem[0]]
содержит PIDmem[0]
й процесс(pid_t) curr_pid
хранит собственный PID для каждого процесса
По сути, только один процесс входит в самый внешний if
блокировать, пока другие "ждут", зацикливаясь, пока не наступит их очередь
1 ответ
Все ваши процессы имеют потоки, связанные с одним и тем же описанием открытого файла, поддерживаемым ядром. Буферы этих потоков принадлежат процессам, но смещение файла принадлежит описанию открытого открытого файла.
Всякий раз, когда процесс читает из потока без буферизованных данных, он, скорее всего, считывает в буфер больше данных, чем сразу же использует. Это то, что происходит в вашем случае. Первый процесс, который читает, считывает все 36 байтов файла в свою копию буфера потока, продвигая базовое смещение файла до конца файла. Процессы, которые впоследствии пытаются читать из потока, не разделяют буфер потока первого; все, что они видят, это то, что (общее) смещение файла располагается в конце файла.
Если вы хотите, чтобы несколько процессов совместно читали из одного и того же файла, вам нужно будет это учитывать. Я вижу как минимум два механизма:
В вашем сегменте разделяемой памяти вы также ведете подсчет количества использованных байтов. Каждый процесс использует это для выполнения
fseek()
в соответствующую позицию, прежде чем он пытается прочитать.Вы используете низкоуровневый ввод-вывод с файловыми дескрипторами (
open()
,read()
) вместо потокового ввода / вывода. Если вы выполняете какую-либо буферизацию, вы сохраняете буфер в разделяемой памяти.
Также обратите внимание, что вам нужна некоторая форма синхронизации, чтобы гарантировать, что каждый процесс видит записи в общую память, выполняемые другими процессами. Вы можете предусмотреть это и избавиться от расточительных спин-блокировок, создав и должным образом используя разделяемый процессом мьютекс и переменную условия.