orzel
orzel

Reputation: 122

Using named pipes and fork in C / Linux

I'm trying to write simple console application that reads text from user, then changes lowercase to uppercase and finally prints result in console. It is working fine when I use only one pipe (e.g. without reading text from console), but works totally unpredictable when I use two.

Shouldn't '[Write]' wait for '[To upper]' until it send text?

I got following output:

[Write] Waiting for txt to diplay.
[To upper] Waiting for txt to change.
[Write] Received following txt:
[To upper] Received txt ().
[To upper] Changed txt send to [Write] ().
[Scan] Type your txt:
[Scan] Txt received. Sending to [To upper] (y)

My code:

#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#define SIZE 16
int main()
{
    int i=0;
    int f1,f2;
    char x[SIZE]={0};
    if( fork() )    
    {
        if( fork() )//[Write]
        {
            f1=open("upper-write",O_RDONLY);
            puts( "[Write] Waiting for txt to diplay." );
            read( f1, &x, sizeof( x ) );
            printf( "[Write] Received following txt: %s\n", x );
            close( f1 );
        }
        else//[Scan]
        {
            puts( "[Scan] Type your txt: " );
            //scanf ("%15s",x);//scanf not working now, so I change my char array by myself     
            x[0]='y';
            f2=open("scan-upper",O_WRONLY);
            printf( "[Scan] Txt received. Sending to [To upper] (%s)\n", x );
            write( f2, &x, sizeof( x ) );
            close( f2 );
        }
    } 
    else//[To upper]
    {
        puts( "[To upper] Waiting for txt to change." );
        f2=open("scan-upper",O_RDONLY);
        read( f2, &x, sizeof( x ) );
        close( f2 );

        printf( "[To upper] Received txt (%s).\n" ,x);  
        for(i=0;i<SIZE;i++)
            if(x[i]>=97 && x[i] <=122)//lowercase -> uppercase
                x[i]-=32;


        f1=open("upper-write",O_WRONLY);
        write( f1, &x, sizeof( x ) );
        printf( "[To upper] Changed txt send to [Write] (%s).\n" ,x);
        close( f1 );
    }
}

Upvotes: 1

Views: 917

Answers (2)

Sean
Sean

Reputation: 5480

I think you need to understand a couple of things to understand the problem. First, after a fork() there's no guarantee as to which process gets to run first. Second, read() returns immediately with a value of zero if the other end of the pipe isn't open for writing.

You're counting on the processes running in a certain order so that the pipes are all open on both sides before any reads take place. Since that doesn't always happen, read() isn't always blocking.

You can solve this by opening both ends of all of your pipes before you fork(). All of the processes will have file descriptors to both ends of the pipes. Just call close() on the file descriptors you don't need in the corresponding processes.

Upvotes: 2

Wouter Verhelst
Wouter Verhelst

Reputation: 1292

Are you sure this isn't because your non-scan processes don't close stdin? You might want to do something like "close(0)" after the fork.

Alternatively, there's popen(), which might be interesting for this kind of stuff.

Upvotes: -1

Related Questions