Несколько дочерних процессов + чтение из потока
Ссылаясь на мой последний вопрос (" Множественный дочерний процесс"), я сейчас пытаюсь сделать реализацию внешней сортировки с использованием нескольких дочерних процессов.
...
fp = fopen(pathname, "r"); // open inputfile in r mode
fgets(trash, 10, fp); // ignore first line
for (i=0; i<numberOfProcess; ++i) {
#ifdef DBG
fprintf(stderr, "\nDBG: Calling fork()\n");
#endif
if ((pids[i] = fork()) < 0) {
perror("fork error");
exit(EXIT_FAILURE);
} else if (pids[i] == 0) { // Child Code
if (numbersToSort % numberOfProcess == 0) { // 16 % 4 = 0
partialDataSize = numbersToSort / numberOfProcess;
for (j=0; j<partialDataSize; j++) {
fscanf(fp, "%d", &arrayPartialData[j]);
qsort(arrayPartialData, partialDataSize, sizeof(int), (void *)comp_num);
//printf("%d\n", arrayPartialData[j]);
// TODO: qsort data until partialDataSize
}
}
printf("pid: %d child process %d outputs: ", getpid(), pids[i]);
printArray(arrayPartialData, partialDataSize);
//break;
exit(0);
}
}
/* Wait for children to exit. */
while (numberOfProcess > 0) {
pid = wait(&status);
--numberOfProcess;
}
fclose(fp);
но, конечно, этот код выводит ту же последовательность отсортированных целых чисел из входного файла из-за fscanf.. например, если начало входного файла включает 5 1 4, то он выводит:
(1-й ребенок) 1 4 5
(2-й ребенок) 1 4 5
(с двумя дочерними процессами).. потому что fscanf начинает читать целые числа с начала входного потока.
Моя проблема сейчас в том, как мне продолжить читать числа, начиная с того места, где ушел предыдущий дочерний процесс? например, если входной файл содержит 5 1 4 8 5 10, он может вывести:
(1-й ребенок) 1 4 5
(2-й ребенок) 5 8 10
заранее спасибо;)
4 ответа
Я бы использовал более низкий уровень open() и read(), а не эквивалентный поток, так как в противном случае вам придется беспокоиться о синхронизации буферов stdio с базовым файловым дескриптором. Обратите внимание, что у вас все еще будут проблемы с чтением полных чисел, поэтому вам, вероятно, потребуется некоторая синхронизация между процессами.
В качестве альтернативы я бы предложил одному процессу прочитать файл и записать подмножество строк в подпроцессы, выполняющие сортировку (используя pipe()), которые они затем записывают в другой процесс, выполняющий слияние.
Если вы используете fscanf, единственное, что вы можете сделать, - это прочитать каждый процесс и сбросить числа до тех пор, пока он не достигнет тех, с которыми он должен работать. В вашем случае откажитесь от i*partdatasize номеров.
Например, 5 7 3 1 4 8 5 10 2 у вас может быть 5 7 3
1 4 8
5 10 2
что бы дать
3 5 7
1 4 8
2 5 10.
Затем вы должны решить, как объединить отсортированные результаты.
Вы работали со связанными каналами.
из glibc 13.5.1 (акцент мой)
Каналы, которые приходят из одного открытия, имеют одинаковую позицию файла; мы называем их связанными каналами. Связанные каналы возникают, когда вы создаете поток из дескриптора с помощью fdopen, когда вы получаете дескриптор из потока с fileno, когда вы копируете дескриптор с dup или dup2, и когда дескрипторы наследуются во время fork.
По-видимому, вы не можете делать ввод / вывод из обоих потоков одновременно.
Если вы использовали поток для ввода-вывода (или только что открыли поток), и вы хотите выполнить ввод-вывод, используя другой канал (поток или дескриптор), который связан с ним, вы должны сначала очистить поток, который вы использовали.
Если вы можете хранить ваши целые числа в двоичном виде. Вы можете прочитать первый поток, это блок
fread(&arrayPartialData[j], sizeof(int), partialDataSize, fp);
Затем второй поток может пропустить уже прочитанный блок (потому что вы знаете размер каждого блока). После этого вы можете начать чтение без необходимости сбрасывать какие-либо данные.
fseek(partialDataSize * threadNumber);
Я также рекомендую использовать темы, так как разветвление очень дорого. учебник темы