Несколько дочерних процессов + чтение из потока - PullRequest
2 голосов
/ 18 мая 2009

ссылаясь на мой последний вопрос ( Множественный дочерний процесс ), я сейчас пытаюсь создать реализацию внешней сортировки с использованием нескольких дочерних процессов.

...
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 ]

1 голос
/ 18 мая 2009

Я бы использовал более низкий уровень open () и read (), а не эквивалентные потоки, так как в противном случае вам придется беспокоиться о синхронизации буферов stdio с базовым файловым дескриптором. Обратите внимание, что у вас все еще будут проблемы с чтением полных чисел, поэтому вам, вероятно, потребуется некоторая синхронизация между процессами.

В качестве альтернативы я бы предложил одному процессу прочитать файл и записать подмножество строк в подпроцессы, выполняющие сортировку (используя pipe ()), которые они затем записывают в другой процесс, выполняющий слияние.

0 голосов
/ 12 октября 2016

Вы работали со связанными каналами.

из glibc 13.5.1 (акцент мой)

Каналы, которые поступают из одного открытия, совместно используют одну и ту же позицию файла; мы называем их связанными каналами . Связанные каналы возникают, когда вы создаете поток из дескриптора с помощью fdopen, когда вы получаете дескриптор из потока с fileno, когда вы копируете дескриптор с dup или dup2, и когда дескрипторы наследуются во время fork. 1012 *

По-видимому, вы не можете выполнять ввод-вывод из обоих потоков одновременно.

Если вы использовали поток для ввода-вывода (или только что открыли поток) и хотите выполнить ввод-вывод с использованием другого канала (либо потока, либо дескриптора), который связан с ним, вы должны сначала очистите поток, который вы использовали.

0 голосов
/ 18 мая 2009

Если вы можете хранить ваши целые числа в двоичном виде. Вы можете прочитать первый поток, это блок

fread(&arrayPartialData[j], sizeof(int), partialDataSize, fp);

Чем 2-й поток может пропустить уже прочитанный блок (потому что вы знаете размер каждого блока). После этого вы можете начать чтение без необходимости сбрасывать какие-либо данные.

fseek(partialDataSize * threadNumber);

Я также рекомендую использовать темы, так как разветвление очень дорого. учебник по темам

0 голосов
/ 18 мая 2009

Если вы используете 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.

Затем вы должны решить, как объединить отсортированные результаты.

...