tags:

views:

389

answers:

3

Hi!

I've written two programs: the first, the "writer", creates a FIFO and writes data into it. The second one, the "reader" runs in background and looks for data in the FIFO. Once data is there, the reader reads it out.

If I start e.g. two writers and two readers, they all can write/read into/from the same FIFO. How can I restrict it for 3rd and 4th readers/writers to use the FIFO and allow only one writer and one reader to use the FIFO?

thanks a lot.

-- kind regards, Max Krug

+1  A: 

Create the FIFO using pipe(2), and only give the file descriptors for each end of the FIFO to the appropriate process when they get forked from the parent process. (Alternatively, have the reader call pipe(2) and fork the writer, or vice versa.) Since the FIFO never lives on the filesystem, it's impossible for any other process to access it.

If you must use a named FIFO, delete the FIFO after the reader and writer have opened it. The underlying FIFO will still exist as long as the reader and writer have it open, but no new processes will be able to open it. However, there will be a race condition where a second reader or writer could open the FIFO before you've deleted it.

Paul Kuliniewicz
Thank you very much, Paul! it looks like it works.I have to use named pipes (FIFOs), so I just added a remove("namedpipe"); behind the write() statement in the reader program.now if I start 2 writers and 2 readers, only 1 writer can write and only 1 reader can read.
Max Krug
lol, sometimes it works and sometimes not, no idea why...
Max Krug
@Max Krug: Define "not working".
Paul Kuliniewicz
more than one writer but only one reader can access the file.
Max Krug
If you delete the FIFO after the reader opens it, there's nothing to stop another writer from creating a new FIFO with the same name. If you're still having trouble, post the code, in case there's some other issue going on.
Paul Kuliniewicz
A: 

FIFO Writer:

 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <fcntl.h>

#define BUFFERSIZE 50
#define CHMOD 0777



int main(int argc, char **argv)     
{  
   char outbuf[BUFFERSIZE]; // outbuffer
   int fifo, j, anzahl;
   // fifo - pipe file deskriptor, j - counter, anzahl - Parameter.

   if(argc!=2)               // Check if parameter is ok
   {                            
       printf("Ungültiger Parameter! Bsp.: ./fifow 10\n");  
       return 1;
   }

   anzahl=atoi(argv[1]);        // convert paramter to integer


   mkfifo("namedpipe4", CHMOD);         // make FIFO "namedpipe4"
   fifo = open("namedpipe4",O_WRONLY);      // open FIFO
   //
   for(j=0;j<anzahl;j++)
     {   

         printf("Writer PID: %d writes record nr. %6d\n", getpid(), j+1);
         sprintf(outbuf, "Writer PID: %d writes record nr. %6d\n", getpid(), j+1); 
         write(fifo, outbuf, BUFFERSIZE);       
         remove("namedpipe4");  // removing the fifo
         sleep(1);              // Wait 1 sec
     }

   close(fifo);  // 

   exit(0);

}

FIFO Reader:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>

#define BUFFERSIZE 50

int main(void)      
{  

   char inbuf[BUFFERSIZE];  // inbuffer
   int fifo, var;

   printf("\n Waiting for a Pipe....\n");

   while((fifo = open("namedpipe4",O_RDONLY)) == -1) // while "there is no such pipe"
   {
    remove("namedpipe4");
    sleep(1);
   }    


   while((var = read(fifo, inbuf, BUFFERSIZE)) > 0) // while "i can read"
   {    
     printf("Reader PID: %d reads  record: %s\n", getpid(), inbuf);
     sleep(1);
   }



   close(fifo);     // 

   printf("\n EOF..\n");

   exit(0);


}
Max Krug
For future reference, you can always edit your questions after you post them (rather than posting updates as answers to your questions, which is all kinds of semantically bad)
jasonmp85
+2  A: 

Given the code you posted in a separate answer, here is a modified version that fixes the problems you were having. See the comments for details, but in a nutshell:

  • The writer checks the return value of mkfifo is checked to see if another writer already created the pipe.
  • The reader gets an exclusive advisory lock on the pipe (via flock) after opening it, to avoid the race condition where a second reader could have opened the pipe before the first reader deleted it.

Writer:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>   /* needed for mkfifo */
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>

#define BUFFERSIZE 50
#define CHMOD 0777

int
main (int argc, char **argv)     
{  
    char outbuf[BUFFERSIZE];
    int fifo, j, anzahl;

    if (argc != 2)
    {                            
        printf("Ungültiger Parameter! Bsp.: ./fifow 10\n");  
        return 1;
    }

    anzahl=atoi(argv[1]);

    /* mkfifo fails if the file already exists, which means there's a
     * writer waiting for a reader.  This assures that only one writer
     * will write to the pipe, since it only opens the pipe if it was
     * the one who created it.
     */
    if (mkfifo("namedpipe4", CHMOD) == -1)
    {
        printf("namedpipe4 already exists\n");
        return 1;
    }

    fifo = open("namedpipe4", O_WRONLY);

    for (j = 0; j < anzahl; j++)
    {   
        printf("Writer PID: %d writes record nr. %6d\n", getpid(), j + 1);
        sprintf(outbuf, "Writer PID: %d writes record nr. %6d\n", getpid(), j + 1); 
        write(fifo, outbuf, BUFFERSIZE);       
        remove("namedpipe4");
        sleep(1);
    }

    close(fifo);

    exit(0);
}

Reader:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/file.h>   /* for flock */
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>

#define BUFFERSIZE 50

int
main (int argc, char **argv)      
{  
    char inbuf[BUFFERSIZE];
    int fifo, var;

    printf("\n Waiting for a Pipe....\n");

    /* There are *two* ways the open can fail: the pipe doesn't exist
     * yet, *or* it succeeded, but a different writer already opened
     * it but didn't yet remove it.
     */
    while (1)
    {
        while ((fifo = open("namedpipe4", O_RDONLY)) == -1)
        {
            /* Since you didn't specify O_CREAT in the call to open, there
             * is no way that namedpipe4 would have been created by the
             * reader.  If there *is* now a namedpipe4, a remove here
             * would delete the one the writer created!
             */
            sleep(1);
        }    

        /* Get an exclusive lock on the file, failing if we can't get
         * it immediately.  Only one reader will succeed.
         */
        if (flock (fifo, LOCK_EX | LOCK_NB) == 0)
            break;

        /* We lost the race to another reader.  Give up and wait for
         * the next writer.
         */
        close (fifo);
    }

    /* We are definitely the only reader.
     */

    /* *Here* we delete the pipe, now that we've locked it and thus
     * know that we "own" the pipe.  If we delete before locking,
     * there's a race where after we opened the pipe, a different
     * reader also opened, deleted, and locked the file, and a new
     * writer created a new pipe; in that case, we'd be deleting the
     * wrong pipe.
     */
    remove("namedpipe4");

    while ((var = read(fifo, inbuf, BUFFERSIZE)) > 0)
    {    
        printf("Reader PID: %d reads  record: %s\n", getpid(), inbuf);
        /* No need to sleep; we'll consume input as it becomes
         * available.
         */
    }

    close(fifo);
    printf("\n EOF..\n");
    exit(0);
}
Paul Kuliniewicz