0

親プロセスと 2 人の子供がいます。親プロセスは、リーダーとカウンターの 2 つの子のみを作成し、その終了を待ちます。子どもたちは次のことを行います。

最初の子 (リーダー):

  1. ファイルを開き、
  2. 一行読み、
  3. シグナル (SIGUSR1) を 2 番目の子に送信し、
  4. 2 番目の子からのシグナルを待ち、
  5. 次の行が読める場合は 2 に進み、そうでない場合は 2 番目の子を殺します。

2 番目の子 (カウンター):

  1. リーダーからのシグナル (SIGUSR1) を待ちます。
  2. 行の長さをカウントし、
  3. リーダーにシグナルを送信し、1 に移動します。

別のプロセスからのシグナルを待つのに問題があります。関数を呼び出す前にシグナルを受信できますpause()。つまり、プロセスを永久にブロックできます。sigprocmask()、 、sigsuspend()も使用しようとしましsigwaitinfo()たが、正しく動作しません。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <signal.h>
#include <string.h>

enum { MAX_LEN = 16 };

void handler(int signo)
{
    // do nothing
}

int main(int argc, const char * argv[])
{
    sigset_t ss;
    sigemptyset(&ss);
    sigaddset(&ss, SIGUSR1);

    // handle SIGUSR1
    signal(SIGUSR1, handler);

    // shared memory for file line
    char *data = mmap(NULL, MAX_LEN, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);

    pid_t *pid_counter = mmap(NULL, sizeof(*pid_counter), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);

    pid_t pid_reader;
    if (!(pid_reader = fork())) {
        sigprocmask(SIG_BLOCK, &ss, NULL);
        printf("READER: waiting signal from COUNTER\n"); fflush(stdout);
        sigwaitinfo(&ss, NULL);
        sigprocmask(SIG_UNBLOCK, &ss, NULL);
        printf("READER: got signal\n"); fflush(stdout);

        printf("READER: opening file\n"); fflush(stdout);
        FILE *f = fopen(argv[1], "r");
        while (fgets(data, MAX_LEN, f) > 0) {
            printf("READER: reading line and waiting signal from COUNTER\n"); fflush(stdout);

            sigprocmask(SIG_BLOCK, &ss, NULL);
            kill(*pid_counter, SIGUSR1);
            sigwaitinfo(&ss, NULL);
            sigprocmask(SIG_UNBLOCK, &ss, NULL);

            printf("READER: got signal\n"); fflush(stdout);
        }
        printf("READER: closing file and killing COUNTER\n"); fflush(stdout);
        fclose(f);
        kill(*pid_counter, SIGTERM);
        _exit(0);
    }

    if (!(*pid_counter = fork())) {
        sleep(1);
        printf("COUNTER: send signal to READER that COUNTER is ready\n"); fflush(stdout);
        while (1) {
            sigprocmask(SIG_BLOCK, &ss, NULL);
            kill(pid_reader, SIGUSR1);
            printf("COUNTER: waiting signal from READER\n"); fflush(stdout);
            sigwaitinfo(&ss, NULL);
            sigprocmask(SIG_UNBLOCK, &ss, NULL);
            printf("COUNTER: got signal\n"); fflush(stdout);

            printf("%d\n", strlen(data));
            fflush(stdout);
        }
    }

    wait(NULL);
    wait(NULL);

    return 0;
}

このコードでは、次のシーケンスを取得できます。

$ gcc -o prog prog.c && ./prog input.dat
READER: waiting signal from COUNTER
COUNTER: send signal to READER that COUNTER is ready
COUNTER: waiting signal from READER
READER: got signal
READER: opening file
READER: reading line and waiting signal from COUNTER
READER: got signal
READER: reading line and waiting signal from COUNTER
READER: got signal
READER: reading line and waiting signal from COUNTER
READER: got signal
READER: reading line and waiting signal from COUNTER
READER: got signal
READER: reading line and waiting signal from COUNTER
READER: got signal
READER: reading line and waiting signal from COUNTER
READER: got signal
READER: closing file and killing COUNTER

なぜカウンターは「信号を得た」と書かないのですか? シグナルを同期的に送受信するにはどうすればよいですか? (他の IPC メソッドについては知っていますが、シグナルによる同期が必要です。)

4

1 に答える 1