0

シグナルとフォークを使用してファイルのコンテンツを読み取り、それを stdout (低レベル I/O) に書き戻す必要があるプロジェクトがあります。親プロセスと子プロセスの間で読み取りと書き込みの作業を分割する必要があり、最初に親プロセスを開始して、ファイルのコンテンツの読み取りと書き込みを行う必要があります。親プロセスが終了したら、シグナル SIGUSR1 を子プロセスに送信して、次のデータ ブロックの読み取りと書き込みを開始できるようにする必要があります。読み書き部分は正常に動作しますが、信号部分と処理部分に問題があります。プログラムを実行すると、正しい出力が表示されますが、終了しません。誰かが私のコードの何が問題なのかをチェックできますか?

これが私がこれまでに得たものです:

#define _XOPEN_SOURCE 600

#include <limits.h> /* For LONG_MAX */
#include <fcntl.h> /*For open()*/
#include <unistd.h> /*For close(), read(), write(), nice()*/
#include <stdlib.h> /*For exit()*/
#include <stdio.h> /*For fprintf(),perror()*/
#include <signal.h> /*For signal()*/
#include <sys/types.h> /* For pid_t */
#include <sys/wait.h> /* For wait() */

void my_handler(int);
void displayUsage(FILE *, const char *);

int main(int argc, char **argv) {

        char c[BUFSIZ]; /* To hold the string that has been read from the file */
        int fd; /* file descriptor */
        int n;
        long int nBytes; /* To hold the number of bytes to read */
        pid_t pid;
        int child_status;

        /* Display usage if user use this process wrong */
        if(argc != 3){
            displayUsage(stderr, argv[0]);
            exit(1);
        }

        /* Convert argv[1] to long - number of bytes to read */
        nBytes = strtol(argv[1], NULL, 10);
        if((nBytes <= 0) || (nBytes > INT_MAX)){
            fprintf(stderr, "Bufferize %s is not a positive integer\n",
             argv[1]);
            exit(2);
        }

        /* Open a file */
        if((fd = open(argv[2],O_RDONLY,0)) < 0){
           perror(argv[2]);
           exit(3);
        }

        /* Attempt to register a signal handler */
        if(signal(SIGUSR1, my_handler) == SIG_ERR){
           perror("Could not set a handler for SIGUSR1");
           exit(4);
        }

        /* lowering the process priority */
        if(nice(40) < 0){
           perror("Cannot lower the priority");
           exit(5);
        }

        /* Create a new process */
        pid = fork();
        if(pid < 0){
           exit(6);
        }
        /* Allocating memory space for string/data to be read from the file
        if(!(c = malloc(nBytes))){
           perror("ERROR");
           exit(4);
        }*/

        if(pid == 0){
           pause();
           /* I'm the child */
           printf("Child's turn!\n");

           /* Read The File */
           while((n = read(fd, c, nBytes)) != 0){
                  /* Write content of 'c' to the stdout */
                  if(write(STDOUT_FILENO, c, n) < 0){
                         perror("Write Error!\n");
                         exit(7);
                  }
           }
           kill(pid,SIGUSR1);

        }
        else{
           /* I'm the parent */
           printf("Parent's turn!\n");
           /* Read The File */
           while((n = read(fd, c, nBytes)) != 0){
                 /* Write content of 'c' to the stdout */
                 if(write(STDOUT_FILENO, c, n) < 0){
                          perror("Write Error!\n");
                          exit(7);
                 }
           }
           /* Reap the child */
           wait(&child_status);
           kill(pid, SIGUSR1);
         }
         pause();

         /* Close the file */
         if(close(fd) < 0){
            perror(argv[2]);
            exit(8);
         }

         exit(0);
}

void displayUsage(FILE *fp, const char *arg){

        fprintf(fp, "Usage: %s n filename\n", arg);
        fprintf(fp, "where\n");
        fprintf(fp, 
            "\tn\tNumber of bytes to read and write in each \"block\".\n");
        fprintf(fp,"\tfilename\tName of file to be catted.\n");
}

void my_handler(int sig){
        /* Re-registering the handler */
        if(signal(SIGUSR1, my_handler) == SIG_ERR){
             perror("Could not set a handler for SIGUSR1");
             exit(4);
        }

        /*if(isParent == 1){
             printf("Parent's turn!\n");
          }
          else{
             printf("Child's turn!\n");
          }*/
}
4

1 に答える 1

4

あなたの問題は、子供が死ぬのを待ってから、ファイルを読みに行くように信号を送ることだと思います。

あなたが持っている:

       /* Reap the child */
       wait(&child_status);
       kill(pid, SIGUSR1);

おそらく次のものが必要です。

       kill(pid, SIGUSR1);
       /* Reap the child */
       wait(&child_status);

あなたの問題の他の部分は、子がpause()終了する前に2番目に到達する可能性がありますが、その時点でプロセスがシグナルを送信しません。そして、親はまだ子が死ぬのを待っていますが、誰かが を壊す信号を送るまで子は終了できませんpause()


そして、もう少し実験を行った後 (さらに多くの診断出力を行った後)、親によって出力されたファイル (ソース コード) とそれに続く情報を取得しました。

Parent sending signal to child
Parent waiting for child
Child (56243) about to pause()

一見すると、子が一時停止される前にシグナルが子に送信されたため、シグナルは送信されていない可能性があります。コードは熱心にフラッシュしていたので、子のシグナル ハンドラーからのトレースが表示されなかった理由がよくわかりません。


顔を爆破するための素敵な単純な問題のようなものはありません...

少し驚かれるかもしれませんが、期待どおりの動作をする修正されたコードを次に示します。

#define _XOPEN_SOURCE 600

#include <limits.h> /* For LONG_MAX */
#include <fcntl.h> /*For open()*/
#include <unistd.h> /*For close(), read(), write(), nice()*/
#include <stdlib.h> /*For exit()*/
#include <stdio.h> /*For fprintf(),perror()*/
#include <signal.h> /*For signal()*/
#include <sys/types.h> /* For pid_t */
#include <sys/wait.h> /* For wait() */

static volatile sig_atomic_t sigusr1 = 0;

void my_handler(int);
void displayUsage(FILE *, const char *);

int main(int argc, char **argv)
{
    char c[BUFSIZ]; /* To hold the string that has been read from the file */
    int fd; /* file descriptor */
    int n;
    long int nBytes; /* To hold the number of bytes to read */
    pid_t pid;
    int child_status;

    /* Display usage if user use this process wrong */
    if(argc != 3){
        displayUsage(stderr, argv[0]);
        exit(1);
    }

    /* Convert argv[1] to long - number of bytes to read */
    nBytes = strtol(argv[1], NULL, 10);
    if((nBytes <= 0) || (nBytes > INT_MAX)){
        fprintf(stderr, "Bufferize %s is not a positive integer\n",
                argv[1]);
        exit(2);
    }

    /* Open a file */
    if((fd = open(argv[2],O_RDONLY,0)) < 0){
        perror(argv[2]);
        exit(3);
    }

    /* Attempt to register a signal handler */
    if(signal(SIGUSR1, my_handler) == SIG_ERR){
        perror("Could not set a handler for SIGUSR1");
        exit(4);
    }

    /* lowering the process priority */
    if(nice(40) < 0){
        perror("Cannot lower the priority");
        exit(5);
    }

    /* Create a new process */
    pid = fork();
    if(pid < 0){
        perror("fork");
        exit(6);
    }
    /* Allocating memory space for string/data to be read from the file
       if(!(c = malloc(nBytes))){
       perror("ERROR");
       exit(4);
       }*/

    if(pid == 0){
        printf("Child (pid = %d) about to signal self (sigusr1 = %d)\n", (int)getpid(), (int)sigusr1);
        fflush(0);
        kill(pid, SIGUSR1);
        printf("Child (%d) about to pause() (sigusr1 = %d)\n", (int)getpid(), (int)sigusr1);
        fflush(0);
        pause();

        /* I'm the child */
        printf("Child's turn %d!\n", (int)getpid());

        /* Read The File */
        while((n = read(fd, c, nBytes)) != 0){
            /* Write content of 'c' to the stdout */
            if(write(STDOUT_FILENO, c, n) < 0){
                perror("Write Error!\n");
                exit(7);
            }
        }
        printf("Child signalling parent\n");
        kill(pid,SIGUSR1);
        printf("Child exiting (status = 37)\n");
        exit(37);
    }
    else{
        /* I'm the parent */
        printf("Parent's turn! (pid = %d, kid = %d)\n", (int)getpid(), (int)pid);
        /* Read The File */
        while((n = read(fd, c, nBytes)) != 0){
            /* Write content of 'c' to the stdout */
            if(write(STDOUT_FILENO, c, n) < 0){
                perror("Write Error!\n");
                exit(7);
            }
        }
        printf("Parent sleeping\n");
        sleep(1);
        printf("Parent sending signal to child\n");
        fflush(0);
        kill(pid, SIGUSR1);
        printf("Parent waiting for child\n");
        fflush(0);
        /* Reap the child */
        int corpse = wait(&child_status);
        printf("waiting over: pid = %d, status = 0x%.4X\n", corpse, child_status);
    }

    printf("%d skipping final pause\n", (int)getpid());
    /*pause();*/

    /* Close the file */
    if(close(fd) < 0){
        perror(argv[2]);
        exit(8);
    }

    printf("%d exiting\n", (int)getpid());
    return(0);
}

void displayUsage(FILE *fp, const char *arg)
{
        fprintf(fp, "Usage: %s n filename\n", arg);
        fprintf(fp, "where\n");
        fprintf(fp, 
            "\tn\tNumber of bytes to read and write in each \"block\".\n");
        fprintf(fp,"\tfilename\tName of file to be catted.\n");
}

void my_handler(int sig)
{
    /* Re-registering the handler */
    if(signal(sig, my_handler) == SIG_ERR){
        perror("Could not set a handler for SIGUSR1");
        exit(4);
    }
    sigusr1 = 1;
    printf("In signal handler (pid %d)\n", (int)getpid());
    fflush(0);
}

出力例:

$ ./doze 20 file.1
Parent's turn! (pid = 56459, kid = 56460)
0.0
Parent sleeping
Child (pid = 56460) about to signal self (sigusr1 = 0)
In signal handler (pid 56460)
Child (56460) about to pause() (sigusr1 = 1)
In signal handler (pid 56459)
Parent sending signal to child
Parent waiting for child
In signal handler (pid 56460)
Child's turn 56460!
Child signalling parent
In signal handler (pid 56460)
Child exiting (status = 37)
In signal handler (pid 56459)
waiting over: pid = 56460, status = 0x2500
56459 skipping final pause
56459 exiting
$

データ ファイル には、 (非常につまらない)file.1を含む 1 行が含まれています。0.0ご覧のとおり、親はファイルを正常にコピーします。これで、 のおかげsleep(1)で、子は何かを行う機会を得て、シグナル ハンドラーから目を覚ますことができます。ファイルの残りを標準出力にコピーします...

子供がコピーしたものが見えないのは何ですか?まぁ...

2 つのプロセスは開いているファイル記述を共有し、ファイル内の現在の位置は、開いているファイル記述内の位置によって制御されます。そのため、親がファイルの読み取りを終了すると、ファイルは EOF にあるため、read()子による最初のファイルは 0 バイトになります。lseek(fd, 0L, SEEK_SET);ファイルを再度読み取るには、 を実行する必要があります。

そのため、子はデータをコピーし、親に信号を送って、ステータス 37 で終了します。親が応答するなど、終了まで続きます。したがって、編集したとおりに機能します。一時停止が多すぎました。が必要かどうかはわかりませんが、sleep()必要だと思います。


詳細: メッセージChild signalling parentは不正確な情報です。それは、自分自身にシグナルを送る子です。それは必要ないと思います。実際、これは 40 行少ない「同じ」コードです。

#define _XOPEN_SOURCE 600

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

void my_handler(int);
void displayUsage(FILE *, const char *);

int main(int argc, char **argv)
{
    char c[BUFSIZ];
    int fd;
    int n;
    long int nBytes;
    pid_t pid;
    int child_status;

    if(argc != 3){
        displayUsage(stderr, argv[0]);
        exit(1);
    }

    nBytes = strtol(argv[1], NULL, 10);
    if((nBytes <= 0) || (nBytes > BUFSIZ)){
        fprintf(stderr, "Buffer size %s is not a positive integer between 1 and %d\n",
                argv[1], BUFSIZ);
        exit(2);
    }

    if((fd = open(argv[2], O_RDONLY, 0)) < 0){
        perror(argv[2]);
        exit(3);
    }

    if(signal(SIGUSR1, my_handler) == SIG_ERR){
        perror("Could not set a handler for SIGUSR1");
        exit(4);
    }

    pid = fork();
    if(pid < 0){
        perror("fork");
        exit(6);
    }

    if(pid == 0){
        printf("Child (%d) about to pause()\n", (int)getpid());
        pause();
        printf("Child's turn %d!\n", (int)getpid());
        lseek(fd, 0L, SEEK_SET);
        while((n = read(fd, c, nBytes)) != 0){
            if(write(STDOUT_FILENO, c, n) < 0){
                perror("Write Error!\n");
                exit(7);
            }
        }
        int rc = 37;
        printf("Child exiting (status = %d (0x%.2X))\n", rc, rc);
        exit(rc);
    }
    else{
        printf("Parent's turn! (pid = %d, kid = %d)\n", (int)getpid(), (int)pid);
        while((n = read(fd, c, nBytes)) != 0){
            if(write(STDOUT_FILENO, c, n) < 0){
                perror("Write Error!\n");
                exit(7);
            }
        }
        printf("Parent sleeping\n");
        sleep(1);
        printf("Parent sending signal to child\n");
        kill(pid, SIGUSR1);
        printf("Parent waiting for child\n");
        int corpse = wait(&child_status);
        printf("waiting over: pid = %d, status = 0x%.4X\n", corpse, child_status);
    }

    if(close(fd) < 0){
        perror(argv[2]);
        exit(8);
    }

    printf("%d exiting\n", (int)getpid());
    return(0);
}

void displayUsage(FILE *fp, const char *arg)
{
        fprintf(fp, "Usage: %s n filename\n", arg);
        fprintf(fp, "where\n");
        fprintf(fp, "\tn\tNumber of bytes to read and write in each \"block\".\n");
        fprintf(fp, "\tfilename\tName of file to be catted.\n");
}

void my_handler(int sig)
{
    if(signal(sig, my_handler) == SIG_ERR){
        perror("Could not set a handler for SIGUSR1");
        exit(4);
    }
    printf("In signal handler (pid %d)\n", (int)getpid());
}

出力例:

$ ./doze 20 file.1
Parent's turn! (pid = 56651, kid = 56652)
0.0
Parent sleeping
Child (56652) about to pause()
Parent sending signal to child
Parent waiting for child
In signal handler (pid 56652)
Child's turn 56652!
0.0
Child exiting (status = 37 (0x25))
waiting over: pid = 56652, status = 0x2500
56651 exiting
$

を削除するsleep()と、プログラムが再びハングしました。子が に入る前に、親が子に信号を送信しましたpause()

于 2012-08-14T05:27:04.943 に答える