2

私はLinuxでプロセス管理を学んでおり、子と親がパイプを介して通信する必要があります。2 つの構造体を宣言しました。

typedef struct
{
    double min, max, avg;   /*Number stats*/
} Stats;

typedef struct {
    pid_t pid;      /*Process ID*/
    int first;      /*First number to process*/
    int last;       /*Last number to process*/
    int fd[2];      /*Pipe descriptor*/
    Stats stats;    /*Stats computed by process*/
}Process_list;

数値の配列からいくつかの統計を計算する (作業を分割する) には、M 個の子プロセスが必要です。次に、子プロセスは Process_list 構造体を読み取り、配列内の番号を最初から最後まで処理し (そこに指定されています)、計算された統計を stats 構造に保存します。

コードの問題に最も関連する部分は次のとおりです (何が正常に行われたかを説明するために、他のコードの代わりにコメントを追加しています)。

int main(int argc, char *argv[])
{
    pList=(Process_list *)malloc((M+1)*sizeof(Process_list));
    /*Correct allocation is checked*/

    int i;
    pid_t pid;
    for (i=0 ; i<M ; i++)       /*M clones*/
    {
        /*Fork and pipe creation*/
        pid = fork ();
        pipe(pList[i].fd);

        /*If it's the child*/
        if ( pid == 0 ) 
        {
            pList[i].pid=pid; 
            printf("CHILD %d: %d a %d\n",i, pList[i].first,pList[i].last);

            /*A function here computes stats and saves them OK in the struct*/
            /*(e.g. min is saved in pList[i].stats.max, when printed it's a reasonable value)*/

            /*Now I need to send the info to the parent*/
            ret1=close(pList[i].fd[0]);
            /*ret1=0 => OK */

            ret2=write(pList[i].fd[1], &(pList[i].stats), sizeof(Stats));
            printf("return write: %d\n",ret2);
            /*TROUBLE HERE! This isn't even printed. sizeof(Stats)=24 which I think is OK*/

            exit(EXIT_SUCCESS);
        }

        /*Parent*/
        else if ( pid > 0 )
        {
            wait(NULL); /*Is this really neccesary?*/

            ret1=close(pList[i].fd[1]);
            ret2=read(pList[i].fd[0], &(pList[i].stats), sizeof(Stats));
            /*Both ret1 and ret2 = 0*/

            printf("[p]Mín: %lf\n Max: %lf\nAverage: %lf\n",pList[i].stats.min,pList[i].stats.max,pList[i].stats.avg);
            /*Everything printed here  = 0.0000000000*/


        }

        else /*fork error*/
                return -1;
    }

したがって、私の問題は、子が統計を完全に計算しているのに、親がそれらを受け取っていないことです。write() 関数は何もしません。これは、M のすべての値に対して発生します (M=1 - 1 つのプロセスのみを含む)。

また、wait(NULL) が必要かどうかもわかりません。これを使用しない実際の例をいくつか見たことがあります。ただ、そこに書かないと親のprintfsが子より先に出てしまうので、子がパイプに書き込むのを待たないだけだと思います。とにかくそれなしでは機能しません。

それとも、構造アプローチが適切ではないのでしょうか?

事前にどうもありがとうございました!

4

2 に答える 2

3

フォークする前にパイプを作成する必要があります。そうしないと、2 つのパイプが作成されます。接続されていない親に 1 つ、子供に 1 つ。

そしてwait、すべてのデータを取得した後の子の場合、子がwriteパイプバッファーのクリアをブロックしている場合、永遠に待機することになります。wait死んだ子に関連付けられているリソースを解放します。あなたの子供が死んでいない場合、これは死ぬまで待ちます。

別のこと:fwriteデータのブロック (構造体の配列) をファイル記述子に書き込むために使用します。fread読むために。FILE*ファイル記述子をwithに変換できますfdopen

int main(int argc, char *argv[])
{
pList=(Process_list *)malloc((M+1)*sizeof(Process_list));
/*Correct allocation is checked*/

int i;
pid_t pid;
for (i=0 ; i<M ; i++)       /*M clones*/
{
    /*Fork and pipe creation*/
    if(pipe(pList[i].fd)) {
        perror("pipe");
        return -1;
    }
    pid = fork ();

    /*If it's the child*/
    if ( pid == 0 ) 
    {
        pList[i].pid=pid; 
        printf("CHILD %d: %d a %d\n",i, pList[i].first,pList[i].last);

        /*A function here computes stats and saves them OK in the struct*/
        /*(e.g. min is saved in pList[i].stats.max, when printed it's a reasonable value)*/

        /*this just closes your read end of the pipe*/
        close(pList[i].fd[0]);
        /*ret1=0 => OK */

        FILE* fp = fdopen(pList[i].fd[1], "w");
        while (!fwrite(&(pList[i].stats), sizeof(Stats), 1, fp) && !feof(fp));
        if (feof(fp)) {
            fclose(fp);
            fprintf(stderr, "reader closed his end of the pipe\n");
            return -1;
        }

        // sends eof to reader
        fclose(fp);

        printf("%d bytes written successfully",sizeof(Stats));
        /*TROUBLE HERE! This isn't even printed. sizeof(Stats)=24 which I think is OK*/

        exit(EXIT_SUCCESS);
    }

    /*Parent*/
    else if ( pid > 0 )
    {

        // this is actually nessesary to ensure that the pipe properly closes
        close(pList[i].fd[1]);
        FILE* fp = fdopen(pList[i].fd[0], "r");

        if (!fread(&(pList[i].stats), sizeof(Stats), 1, fp)) {
            fprintf(stderr, "writer sent eof, but not enough data\n");
            return -1;
        }

        fclose(fp);

        printf("[p]Mín: %lf\n Max: %lf\nAverage: %lf\n",pList[i].stats.min,pList[i].stats.max,pList[i].stats.avg);
        /*Everything printed here  = 0.0000000000*/

        wait(0);

    }

    else /*fork error*/
            return -1;
}
于 2012-10-17T17:59:49.683 に答える
0

終了した子の場合、 を実行するとwait()、システムは子に関連付けられたリソースを解放できます。await()が実行されない場合、終了した子は「ゾンビ」状態のままになります。これは一種の安全な方法であり、常に使用することをお勧めします。参照:man -s2 wait

wait(NULL)システムコールは、親プロセスが子プロセスを待機し(この場合、フォークされたばかりの子を待機し)、子プロセスから返されたステータスを保存しないことを意味します。待機をさらに制御したい場合は、以下を確認してくださいman -s2 waitpid。基本的にwait()は、 のバニラ形式ですwaitpid()

さて、パイプ部分。子プロセス内にパイプを作成しています。親プロセスはこれにどのようにアクセスできますか? 実際には、このように機能if a pipe is created in a parent process, the pipe fd's will be copied to the child process.します。その逆ではありません。参照:man -s2 pipe

そのため、親プロセスでパイプを作成してから afork()を発行し、子プロセスでパイプ fd を使用して親に送信します。子write()はパイプの書き込み fd にデータを入れることができるようになり、親コードread()は子プロセスが書き込んだものを受け取ることができるようになりました。

子から親への一方向の IPC 通信を作成しました。したがって、子の読み取り fd を閉じており、親の書き込み fd も閉じています。したがって、そのようにして、子でのみ書き込み、親でのみ読み取ります。ロジックは適切に実装されています。障害はありません。

pipe() の論理的な問題 (親でパイプを作成してからフォークする) を修正すると、コードは意図したとおりに動作するはずです。パイプがデータ型または作成した構造で機能しない理由はありません。

于 2012-10-17T18:55:48.370 に答える