Search code examples
carrayspipebytefwrite

Number of bytes written is always -1


I'm trying to implement some IPC without mutex's,conditions and semaphores, only using pipes. The following code represents a parent process forking in 3 childs (p11,p12,p13) the parent wakes up all the childs with a SIGUSR2 signal,then p11 starts writing 50 random numbers to the pipe. p12 and p13 competitively read from the pipe and write the numbers they get to their own file (file12 and file13). The 50th number is a -1, once the childs read -1, they exit. The write used in the p11 child, just doesn't write a single byte, it returns -1 I can only use write(2) and read(2) calls for writing and reading. I can't seem to be able to implement it, I tried several times with no results. Hope you can help me.

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/wait.h>
void handler(int signo)
{
    printf("\nSignal intercepted!\n");
}

void main ()
{
srand(time(NULL));
signal(SIGUSR2,handler);
int pa[2];
pipe(pa[2]); //create pipe
pid_t pid1,pid2,pid3;
if((pid1=fork())==0)  //child 11
    {
        close(pa[0]); //close the read side of the pipe
        pause();
        int i,nwrite,num;
        for(i=0;i<49;i++)
            {

            num=rand()%100+1; //generate a random number
            nwrite=write(pa[1],&num,sizeof(int)); //write it to the  pipe
            if(nwrite==-1) //if there's a write error
                {
                printf("\nWrite error..\n");
                exit(-1);
                }
            }
        num=-1; //generate the last number
        nwrite=(write(pa[1],&num,sizeof(int))); //write the last number to the pipe
        if (nwrite==-1) //if there's a write error
            {
            printf("\nError,now exiting...\n");
            exit(-1);
            }   
        close(pa[1]); //close the pipe in write mode
        exit(1); 
    }

else if ((pid2=fork())==0) //child 12
    {

    close(pa[1]); //close the write side of the pipe
    pause();
    int fd1,nread,num;
    fd1=open("file12.txt",O_CREAT,0777); //create a new file
    while((nread=read(pa[0],&num,sizeof(num)))>0)  //while there are bytes to read
        {
            if(num!=-1) //if this isn't the last number
                {
            write(fd1,&num,sizeof(num)); //write it to the file
                }
            else
                {   
                printf("\n-1 sent!\n"); //notify the last read number
                close(pa[0]); //close the read side of the pipe
                    close(fd1); //close the file descriptor
                    exit(1); //exit
                    }
            }   
        }



    else if ((pid3=fork())==0) //child 13, same as 12
        {
            close(pa[1]);   
            pause();
            int fd2,nread,num;
            fd2=open("file13.txt",O_CREAT,0777);

            while((nread=read(pa[0],&num,sizeof(num)))>0)
                {
                    if(num!=-1)
                    {
                            write(fd2,&num,sizeof(num));
                    }
                    else
                    {
                        printf("\n-1 sent!\n");
                        close(pa[0]);
                        close(fd2);
                        exit(1);
                    }
                }   
        }




else //parent
    {   
        sleep(1);
        kill(pid1,SIGUSR2); //wake up all the childs
        kill(pid2,SIGUSR2);
        kill(pid3,SIGUSR2);
        waitpid(pid1,0,NULL); //wait for the childs to end
        waitpid(pid2,0,NULL);
        waitpid(pid3,0,NULL);
        printf("\nDone, now exiting...\n"); //exit
    }

}

Solution

  • At least this*1

    int pa[2];
    pipe(pa[2]);
    

    should be

    int pa[2];
    pipe(pa);
    

    Background:

    pa[2] evaluates to int. pipe() on the other hand expects a int[2], which in the context of defining a function's parameter is the same as int[] which is the same as int *.

    If an array gets passed to a function it decays to a pointer its 1st element. So passing pa to pipe() would result in passing &pa[0], which indeed is an int *.


    *1 BTW, coding pa[2] provokes undefined behaviour in any case as it reads out the 3rd element of pa, with pa only having two elements.