2

fork共有メモリに基づくパイプを実装しましたが、プログラムで呼び出そうとすると問題が発生しmainます。

次のメイン:

# include "my_shm_piper.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <sys/mman.h>
int main()
{
    int spd[2], pid, rb;
    char buff[4096];

    fork();  // that fork is okay , but if we put it after initPipe() , there's a deadlock

    initPipe();

    if (my_pipe(spd) < 0)
    {
        perror("my_pipe");
        exit(1);
    }

    if (fork()) 
    {
        rb = my_read(spd[0], buff, sizeof(buff));
        if (rb > 0)
            write(1, buff, rb);
    }

    else
    {
        my_write(spd[1], "hello world!\n", sizeof("hello world!\n"));
    }

    my_close(spd[0]);
    my_close(spd[1]);
    removePipe();
    return 0;
}

共有メモリ ライブラリを使用して実装された匿名パイプを使用しています。

上記のように の1stコマンドを入力するとfork()、プログラムは期待どおりに動作し、すべてのhello-world-s が表示されます。

しかし、forkafterを置くinitPipe()と、デッドロックが発生し、プログラムがハングします。

int main()

{
    int spd[2], pid, rb;
    char buff[4096];

    initPipe();
    fork();   // now the fork() is after the initialization ,and we have a deadlock

    if (my_pipe(spd) < 0)
    {
        perror("my_pipe");
        exit(1);
    }

        // from here the same as above 
}

fork()の初期化段階は、最初の段階のように 2 回ではなく、1 回だけ行われると思いますmain()

書き込み/読み取りの段階で何か問題があると思いますが、正確なソースを見つけることができないようです。

ご協力をお願いいたします。

ありがとう

編集:

H.ファイルの構造体:

struct PipeShm
{
    int init;
    int flag;
    sem_t *mutex;
    char * ptr1;
    char * ptr2;
    int status1;
    int status2;
    int semaphoreFlag;
};

これはinitPipeです:

int initPipe()
{
    if (!myPipe.init)
    {
        myPipe.mutex = mmap (NULL, sizeof *myPipe.mutex, PROT_READ | PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS, -1, 0);
        if (!sem_init (myPipe.mutex, 1, 1))
        {
            myPipe.init = TRUE;
        }
        else
            perror ("initPipe");
    }
    return 1;   // always successful
}

これは my_pipe() です:

int my_pipe(int spd[2])
{
    spd[0] = shmget(2009, SHMSIZE, 0);      // for reading
    spd[1] = shmget(2009, SHMSIZE, 0666 | IPC_CREAT);  // for writing

     if (spd[0] == -1 || spd[1] == -1)
     {
             perror("shmget");
             exit(EXIT_FAILURE);
             return -1;
     }

     return 1;

}

これは読みです:

ssize_t my_read(int spd, void *buf, size_t count)
{

    char array[4096];
    memset (array, '\0', 4096);
    ssize_t returnVal = 0;

    sem_wait (myPipe.mutex);

    int sval;
    sem_getvalue (myPipe.mutex, &sval);

    printf ("my_read - wait %d\n", sval);
    if (sem_wait (myPipe.mutex))
    perror ("sem_wait");

    printf ("my_read - proceed\n");

    if (myPipe.flag == FALSE)
    {
        myPipe.ptr1 = shmat (spd, NULL, 0); // attaching the segment
        if (myPipe.ptr1 == (void *) -1)
            error_out ("shmat");

        strncpy (array, myPipe.ptr1, count);
        array[count] = '\0';

        returnVal = strlen (array);
        buf = (void *) array;

        printf ("Output:%s", array);

    }

    else if (myPipe.flag == TRUE)
    {
        const size_t region_size = sysconf (_SC_PAGE_SIZE);
        myPipe.ptr1 = mmap (0, region_size, PROT_READ | PROT_WRITE, MAP_SHARED, spd, 0);
        if (myPipe.ptr1 == (void *) -1)
            error_out ("mmap");

        strncpy (array, myPipe.ptr1, count);
        array[count] = '\0';

        returnVal = strlen (array);
        buf = (void *) array;

        printf ("Output:%s", array);

    }

    return returnVal;

}

そしてこれは文章です:

ssize_t my_write(int spd, const void *buf, size_t count)
{

       ssize_t returnVal = 0;
       sleep(1); // debug to ensure that read goes first for testing.
        if (myPipe.flag == FALSE)
        {
            myPipe.ptr2 = shmat (spd, NULL, 0); // attaching the segment
            if (myPipe.ptr2 == (void *) -1)
                error_out ("shmat");

            char *d = (char *) buf;

            returnVal = snprintf (myPipe.ptr2, count, "%s", d);
        }
        else
        {
            const size_t region_size = sysconf (_SC_PAGE_SIZE);

            // Map the region into memory.
            myPipe.ptr2 = mmap (0, region_size, PROT_READ | PROT_WRITE, MAP_SHARED, spd, 0);
            if (myPipe.ptr2 == MAP_FAILED)
                error_out ("mmap");
            char *d = (char *) buf;

            returnVal = snprintf (myPipe.ptr2, count, "%s", d);
        }

        sem_post (myPipe.mutex);
        return returnVal;

}

プロセスはそのようにハングしています-2番目のメイン(これはコンソールの出力です):

my_read - wait 0
my_read - proceed
Output:hello world!
// here it just gets stuck

最初の main では、コンソールの出力は次のとおりです。

my_read  - wait 0
my_read  - wait 0
my_read - proceed
my_read - proceed
Output:hello world!
Output:hello world!
// here the program is done , the end 
4

2 に答える 2

2

ああ。トリッキーなものですが、私はそれを理解するのに十分退屈していました。

基本的に、待機と投稿のバランスが取れていません。read() 関数を見ると、次の 2 つの待機が行われます。

sem_wait (myPipe.mutex);
// some more code
if (sem_wait (myPipe.mutex))
  perror ("sem_wait");

しかし、書き込み関数は 1 つの投稿しか行いません。

しかし、フォークが前に発生した場合、なぜ機能するのinitPipe()でしょうか? セマフォを 1 に初期化しているため:

if (!sem_init (myPipe.mutex, 1, 1))

init の前にフォークしているため、値が 1 の 2 つの異なるセマフォがあります。それぞれがポストと 2 回の待機を受け取るので、問題ありません。

それ以外の場合は、値が 1 の単一のセマフォがあり、2 つのポストと 4 つの待機を受け取ります。1 + 2 < 4、あなたのリーダーの1人がハングアップしsem_waitます。

ところで、それはかなり複雑な書き方pipe(2)です。

于 2012-07-28T22:53:06.477 に答える
0

「動作する」コードを考えると、2 つのパイプにそれぞれ 1 つのリーダーと 1 つの書き込みがあります。「動作しない」コードを考えると、2 つのリーダーと 2 つのライターを持つ 1 つのパイプがあり、同じ無名パイプを 2 回作成しようとします。

2 つのリーダーと 2 つのライターの場合、同じパイプを 2 回作成すると、-1 が返され、errno が EEXISTS に設定されます。

于 2012-08-01T00:08:54.910 に答える