親プロセスと 2 人の子供がいます。親プロセスは、リーダーとカウンターの 2 つの子のみを作成し、その終了を待ちます。子どもたちは次のことを行います。
最初の子 (リーダー):
- ファイルを開き、
- 一行読み、
- シグナル (SIGUSR1) を 2 番目の子に送信し、
- 2 番目の子からのシグナルを待ち、
- 次の行が読める場合は 2 に進み、そうでない場合は 2 番目の子を殺します。
2 番目の子 (カウンター):
- リーダーからのシグナル (SIGUSR1) を待ちます。
- 行の長さをカウントし、
- リーダーにシグナルを送信し、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 メソッドについては知っていますが、シグナルによる同期が必要です。)