0

I have a very simple basic program that has two process first one is parent and second one is child.

Child process should write some stuff to the FIFO. After all writing jobs finished(after the child is terminated). Then parent process should read all the FIFO file and print to the stdout.

So I think, I need a wait(NULL); for parent. So the parent will wait until the child is terminated. But child is also blocked because of the writing and blocked for reading this writes. So both process wait each other and I think,there occur an deadlock.

My program is this:

#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, &status, WNOHANG)) == -1)
           perror("wait() error");
        else if (pid == 0) {
            //child running
            printf("child running\n");
        }
        else {
            if (WIFEXITED(status)){
                printf("child is terminated\n");
                printAllFifo();
            }
            else{ 
                printf("child did not exit successfully\n");
            }
        }
    } 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,"foo1\n",strlen("foo1\n"));
    close(fd);

    fd = open(myfifo, O_WRONLY);
    write(fd,"foo2\n",strlen("foo2\n"));
    close(fd);

    fd = open(myfifo, O_WRONLY);
    write(fd,"foo3\n",strlen("foo3\n"));
    close(fd);
}


void printAllFifo (){     //parent process will run this function
    int fd=open(myfifo, O_RDONLY);
    char* readBuffer=(char*)malloc((strlen("foo1\n")+strlen("foo2\n")+strlen("foo3\n"))*sizeof(char));
    read(fd, readBuffer, strlen("foo1\n")+strlen("foo2\n")+strlen("foo3\n"));
    printf("%s\n",readBuffer );
    close(fd);
}
javac
  • 441
  • 4
  • 20

1 Answers1

3

mkfifo() creates a pipe of limited size. You should not wait in the parent process until the child has finished in order to read, you should read constantly in the parent process while checking if the child has terminated already.

You can use ulimit -p in order to read the default size of pipes in your linux system. The number is multiplications of 512, so a value of 8 means 4096 bytes.

Using pipe() is more suited to the task than mkfifo() because you do not actually need a named pipe. this will provide you with 2 fds, one for read and one for write. In the parent code you close the write fd, in the child code you close the read fd, then you can start reading from the pipe in the parent code until it returns a value <= 0. This would mean that the child process has terminated (and the pipe was closed for writing). then you only need to call waitpid() from the parent code to collect the terminated child process.

Shloim
  • 5,281
  • 21
  • 36
  • I still didn't understand how can I solve tihs problem . How can I increase the size of the pipe? Could you explain with codes? – javac Mar 28 '19 at 10:50
  • You do not increase the size. You just read from it before the child terminates. – Shloim Mar 28 '19 at 10:59
  • First, I have to use `fifo` beacuse , I will use it in my homework. Also, if I read from it before the child terminates, the child can't writes all the contents and parent read incompeted file. – javac Mar 28 '19 at 11:03
  • The parent needs to read in a loop until it detects that the pipe was closed for writing. – Shloim Mar 28 '19 at 11:04
  • Okay then , how can I control that pipe was closed for writing? – javac Mar 28 '19 at 11:07
  • You want the pipe to get closed for writing, that's how you detect that the child has finished writing to it. Try opening it for reading before forking, and read from it after forking, but before wait/waitpid – Shloim Mar 28 '19 at 11:21
  • @still I didn't understand, I need to see some codes to understand. You only explain and don't show the codes. – javac Mar 28 '19 at 11:27
  • Please see my edited question ( I add waitpid in main but it is still blocked). – javac Mar 28 '19 at 11:30
  • I don't have anything to add. I've already explained that you need to read in a loop before waitpid. – Shloim Mar 28 '19 at 11:34
  • See my post, I have already do that but it cause an infinite loop. – javac Mar 28 '19 at 11:35
  • @EasterGamer: As Shloim explains, the parent process should read from the pipe without waiting for the child. In the parent, simply create the pipe, fork the child, and enter a **loop** that reads from the pipe until nothing more can be read. The read operations on the pipe will automatically wait until the child has written data into the pipe. In the child, write to the pipe and then exit. The two processes will be automatically coordinated by the system. The parent must accept partial sequences of data as they come through the pipe; it should not expect all the data at once. So it must loop. – Eric Postpischil Mar 28 '19 at 12:18
  • @Eric Postpischil , how can I read ? Byte by byte or line by line? And how to know that there is nothing more can be read? Also could you please give piece of code for this solution ? – javac Mar 28 '19 at 12:36
  • @EasterGamer: Read any number of bytes you want using the `read` function. When `read` returns 0 or −1, it means no more data is available (0 for end of data, −1 for error). You should try to write your own code, because that is better for learning. – Eric Postpischil Mar 28 '19 at 12:40