Как родительский процесс считывает файл FIFO после того, как дочерний процесс завершил запись этого файла FIFO?

#c #linux #named-pipes #fifo #systems-programming

#c #linux #именованные каналы #fifo #системы-программирование

Вопрос:

У меня есть очень простая базовая программа, в которой есть два процесса: первый — это parent и второй — это child .

Дочерний процесс должен записать некоторые данные в FIFO . После завершения всех заданий на запись (после завершения дочернего процесса). Затем родительский процесс должен прочитать весь FIFO файл и распечатать в stdout .

Итак, я думаю, мне нужен wait(NULL); for parent . Таким образом, parent будет ждать, пока child завершится. Но child также блокируется из-за записи и блокируется для чтения этих записей. Итак, оба процесса ожидают друг друга, и я думаю, возникает взаимоблокировка.

Моя программа такова:

 #include <stdio.h> 
#include <unistd.h> 
#include <sys/wait.h> 
#include <sys/types.h> 
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>

int writeSomeStuffToFifo ();
void printAllFifo ();

char * myfifo = "myfifo";

int main(int argc, char **argv) { 

    int pid=0;
    int childPid=-1;
    int status;
    pid=fork();


    if ((pid = fork()) < 0){
        perror("fork() error");
    }
    else if (pid == 0) {
        writeSomeStuffToFifo ();
        exit(1);
    }
    else do {
        if ((pid = waitpid(pid, amp;status, WNOHANG)) == -1)
           perror("wait() error");
        else if (pid == 0) {
            //child running
            printf("child runningn");
        }
        else {
            if (WIFEXITED(status)){
                printf("child is terminatedn");
                printAllFifo();
            }
            else{ 
                printf("child did not exit successfullyn");
            }
        }
    } while (pid == 0);


    return 0;
}


int writeSomeStuffToFifo (){   //child process will run this function
    int fd;
    mkfifo(myfifo, 0666); 

    fd = open(myfifo, O_WRONLY);
    write(fd,"foo1n",strlen("foo1n"));
    close(fd);

    fd = open(myfifo, O_WRONLY);
    write(fd,"foo2n",strlen("foo2n"));
    close(fd);

    fd = open(myfifo, O_WRONLY);
    write(fd,"foo3n",strlen("foo3n"));
    close(fd);
}


void printAllFifo (){     //parent process will run this function
    int fd=open(myfifo, O_RDONLY);
    char* readBuffer=(char*)malloc((strlen("foo1n") strlen("foo2n") strlen("foo3n"))*sizeof(char));
    read(fd, readBuffer, strlen("foo1n") strlen("foo2n") strlen("foo3n"));
    printf("%sn",readBuffer );
    close(fd);
}
  

Ответ №1:

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

Вы можете использовать ulimit -p для чтения размера каналов по умолчанию в вашей системе Linux. Число умножается на 512, поэтому значение 8 означает 4096 байт.

Использование pipe() больше подходит для этой задачи, чем mkfifo() потому что вам на самом деле не нужен именованный канал. это предоставит вам 2 fds, один для чтения и один для записи. В родительском коде вы закрываете поле записи, в дочернем коде вы закрываете поле чтения, затем вы можете начать чтение из канала в родительском коде, пока он не вернет значение <= 0. Это означало бы, что дочерний процесс завершился (и канал был закрыт для записи). тогда вам нужно только вызвать waitpid() из родительского кода, чтобы собрать завершенный дочерний процесс.

Комментарии:

1. Я все еще не понял, как я могу решить проблему tihs. Как я могу увеличить размер канала? Не могли бы вы объяснить с помощью кодов?

2. Вы не увеличиваете размер. Вы просто читаете из него перед завершением дочернего процесса.

3. Во-первых, я должен использовать fifo beacuse, я буду использовать его в своей домашней работе. Кроме того, если я прочитаю из него до завершения дочернего процесса, дочерний процесс не сможет записать все содержимое, и родительский файл не будет прочитан.

4. Родительскому процессу необходимо выполнять чтение в цикле, пока он не обнаружит, что канал был закрыт для записи.

5. Хорошо, тогда как я могу контролировать, чтобы канал был закрыт для записи?