0

I have this kind of pseudo-code and i'm wishing to know what I must change in order to guarantee that the signal send to the parent will indeed arrive after that the parent pauses.

int main()
{
    int pid;
    
    for(int i = 0; i < 5; i++)
    {
        if((pid = fork()) == 0)
        {   
            mapp(i);
        }
    }

    for(int i = 0; i < 5; i++)
    {
        /*Parent opens fifo i for reading*/
        pause(); /*Parent must stop it's execution until child i writes to fifo i*/
        /*Parent reads from the fifo number i => SUCCESS*/ 
    }
    
    
}

void mapp(int i)
{
    /*Children opens fifo i for writing*/
    /*Children writes to fifo i*/
    kill(getppid(), SIGCONT); /*Children notifies it's father so that he's now be able to read*/
}

It seams that there's nothing wrong with the logic right? but sadly, the program will not always run as expected: sometimes the execution will hang, because sometimes (not always) the signal is send before that the parent is even paused, so when the parent pauses the program will hang because it will not receive any other kind of signal.

PD: sleep() is not an option, I must not elongate the execution time of the program.

Thanks!

3
  • If you want to block the parent until the child writes, you could just use read(). Do you have some requirement that says you must use pause()? Nov 13, 2020 at 3:14
  • @AndyDalton so you're telling me that the read() will pause the execution if there's nothing to read? are you sure about that? But even if it works like that, I don't want the parent to inmediately read what the other process writes, because the other process is supposed to write various things depending of some condition, so I want the parent to read just after absolutely everything is writted. PD: Thanks for your comment.
    – Dacaramo
    Nov 13, 2020 at 21:11
  • Does the writer close the file descriptor when it's finished writing? If so, you could always use multiple reads. Trying to enforce some event timing between the processes will be error prone. Nov 14, 2020 at 0:32

1 Answer 1

0

You are right, your program is subject to a race condition.

The solution here would be to create the communication pipes in the parent, rather than having each process create and connect them. You mention they use fifos, but a fifo file is just like a pipe, and since they are family, you probably don't need a fifo and a pipe would suffice.

Very roughly:

#define CHILDREN 5
int main()
{
    int pid;
    int pipes[CHILDREN][2];
    
    for(int i = 0; i < CHILDREN; i++)
    {
        if (pipe(pipes[i]) == -1) {
           // Error
        ]
        
        pid = fork();
        if(pid == -1) {
          // Error
        } else if (pid == 0) {
            // Child   
            close(pipes[i][0]);
            mapp(i, pipes[i][1]);
        } else {
            // Parent
            close(pipes[i][1]);
        }
    }

    for(int i = 0; i < CHILDREN; i++)
    {
        /*Parent reads from the pipe number i => SUCCESS*/ 
        read(pipes[i][0], ...); // Will block until children writes
    }
    
    
}

void mapp(int i, int fd)
{
    /*Children writes to its pipe */
    write(fd, "hello Dad!\n", 11);
}

The parent will block until it can read from the pipe, so it is completely efficient. If you wanted to block until it can read from any of the pipes, you could do it as well, using select, epoll, etc.

Writes to pipes are atomic assuming they are of less than PIPE_BUF (on Linux, that's 4096 bytes). On recent Linux you could use O_DIRECT and have a "packet" mode, too. Although since you would have a pipe per child, this seems unnecessarily.

3
  • I wasn't planning in change the design of my program at that level jaja, I know that the sample that I gave is just pseudo code, but theres a lot of code behind. Anyways I apreciate a lot you're time and did not know that the parent will block until it can read from the comunication pipe soo thanks!!!
    – Dacaramo
    Nov 13, 2020 at 21:22
  • And since you have helped me with your response and you took your time to explain to me, (rather than down voting my question as is usual at this especific stack exchange site), I'll accept your answer, thanks again!
    – Dacaramo
    Nov 13, 2020 at 21:29
  • If you want to keep using fifos, you can create the pipes but use them only for syncrhonization. Have the child write one byte when they are ready and close them. The parent would be waiting on the pipe and continue when it finishes (and by actually providing one byte, you can even differentiate from the child dying for some other reason).
    – Ángel
    Nov 13, 2020 at 23:38

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .