2

私は 2 つのプログラムを作成しました。最初の「ライター」は、FIFO を作成し、そこにデータを書き込みます。2 番目の「リーダー」はバックグラウンドで実行され、FIFO 内のデータを探します。データがそこにあると、リーダーはそれを読み取ります。

たとえば、2 つのライターと 2 つのリーダーを開始すると、それらはすべて同じ FIFO に対して書き込み/読み取りを行うことができます。3 番目と 4 番目のリーダー/ライターが FIFO を使用するように制限し、1 つのライターと 1 つのリーダーのみが FIFO を使用できるようにするにはどうすればよいですか?


私のコード:

FIFO ライター:

 #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 リーダー:

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


}
4

2 に答える 2

4

別の回答に投稿したコードを考えると、これはあなたが抱えていた問題を修正する修正版です。詳細についてはコメントを参照してください。

  • mkfifoライターは、別のライターが既にパイプを作成しているかどうかを確認するために、戻り値がチェックされていることを確認します。
  • flockリーダーは、最初のリーダーがパイプを削除する前に 2 番目のリーダーがパイプを開く可能性があるという競合状態を回避するために、パイプを開いた後に( を介して) パイプの排他的なアドバイザリ ロックを取得します。

ライター:

#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);
}
于 2010-06-03T00:00:38.023 に答える
1

を使用して FIFO を作成し、FIFOpipe(2)の両端のファイル記述子のみを、親プロセスからフォークされたときに適切なプロセスに与えます。(または、リーダーを呼び出しpipe(2)てライターを fork するか、その逆を行います。) FIFO がファイルシステム上に存在することはないため、他のプロセスがそれにアクセスすることは不可能です。

名前付き FIFO を使用する必要がある場合は、リーダーとライターが FIFO を開いた後に FIFO を削除します。基礎となる FIFO は、リーダーとライターが開いている限り存在し続けますが、新しいプロセスはそれを開くことができません。ただし、FIFO を削除する前に 2 番目のリーダーまたはライターが FIFO を開くことができる競合状態が発生します。

于 2010-05-30T15:21:41.223 に答える