UNIX FIFO: Как разрешить FIFO только одной паре писатель / читатель? - PullRequest
2 голосов
/ 30 мая 2010

Я написал две программы: первая, «писатель», создает FIFO и записывает в него данные. Второй, «читатель», работает в фоновом режиме и ищет данные в FIFO. Когда данные есть, читатель их читает.

Если я начну, например, два писателя и два читателя, все они могут писать / читать в / из одного и того же FIFO. Как можно ограничить использование FIFO для 3-го и 4-го читателей / писателей и разрешить использовать только один писатель и один читатель?

Ответы [ 3 ]

4 голосов
/ 03 июня 2010

Учитывая код, который вы разместили в отдельном ответе , вот модифицированная версия, которая устраняет возникшие проблемы. Подробности смотрите в комментариях, но в двух словах:

  • Писатель проверяет возвращаемое значение mkfifo и проверяет, создал ли другой писатель канал.
  • Считыватель получает эксклюзивную консультативную блокировку на канале (через flock) после его открытия, чтобы избежать условия гонки, когда второй считыватель мог открыть канал, прежде чем первый считыватель удалил его.

Автор:

#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);
}

Читатель:

#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);
}
1 голос
/ 30 мая 2010

Создайте FIFO, используя pipe(2), и передайте файловые дескрипторы для каждого конца FIFO соответствующему процессу, когда они разветвляются от родительского процесса. (В качестве альтернативы, пусть ридер вызовет pipe(2) и ответвит писателя, или наоборот.) Поскольку FIFO никогда не живет в файловой системе, любой другой процесс не может получить к нему доступ.

Если вы должны использовать именованный FIFO, удалите FIFO после того, как читатель и писатель откроют его. Базовый FIFO будет существовать до тех пор, пока читатель и писатель его откроют, но никакие новые процессы не смогут его открыть. Тем не менее, будет состояние гонки, при котором второй читатель или писатель может открыть FIFO до того, как вы его удалите.

0 голосов
/ 31 мая 2010

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);


}
...