私は信号で遊んでいます:特にSIGSTOP
とSIGCONT
です。 ここに書いたテストプログラムです。この考え方は、N + 1 プロセスのチェーン(メインプロセスを含む)を作成することです。それぞれが子供が止まるのを待ってから、 そのものを止めなければなりません。主なプロセスは、子供が を停止したときに目を覚まさなければなりません。SIGSTOP/SIGCONT POSIXの振る舞い
これを行うには、f
関数がプロセスチェーンを再帰的に作成します。 の各プロセスは、自身を直接停止する子の の子孫を除いて、SIGCHLD
シグナルでsigsuspendを使用します。その子が停止した場合、 のプロセスはSIGCHLD
シグナルを受信し、そのターンで停止することができます。 メインプロセスがSIGCHLD
シグナルを受信すると、すべての プロセスが停止状態にあることを意味するので、シグナルにSIGCONT
シグナルを送信します。各プロセスはSIGCONT
を自身の子に送信し、最後に終了した最後の子から を除いて終了します。
私はそれを明確にしようとしました:リターンコードテストを削除し、 コメントを書きました。
プログラムを実行すると、すべてが正常であるようですが、SIGCONT
チェーンです。プロセスの中には目を覚ますものもあれば、すべてではないものもあります。 実行中のプログラム(例:ps)を見ると、すべてがうまくいくように見えます:no プロセスをブロックしました。この プログラムで何が間違っているのか分かりません。どんな助けやヒントも大歓迎です。
ここにサンプルトレースがあります。ご覧のとおり、「フォークチェーン」はうまくいっており、プロセスはSIGCHLD
に停止しています。そして、最後の子が生まれて停止します。これは、各プロセスが停止するため、親に「SIGCHLD
チェーン」を作成します。メインプロセスはSIGCHLD
が通知されますと、それはあなたがこのチェーンが完全でないことに気づくことができ目覚めと順番になど、自身の子供にSIGCONT
を送信しますれ、その子にSIGCONT
を送信します。
$ ./bin/trycont
n pid log
0 6257 "suspending on SIGCHLD"
1 6258 "suspending on SIGCHLD"
2 6259 "suspending on SIGCHLD"
3 6260 "suspending on SIGCHLD"
4 6261 "suspending on SIGCHLD"
5 6262 "last child - stopping"
4 6261 "got SIGCHLD"
4 6261 "stopping"
3 6260 "got SIGCHLD"
3 6260 "stopping"
2 6259 "got SIGCHLD"
2 6259 "stopping"
1 6258 "got SIGCHLD"
1 6258 "stopping"
0 6257 "got SIGCHLD"
0 6257 "sending SIGCONT to 6258"
1 6258 "awakened - sending SIGCONT to 6259"
2 6259 "awakened - sending SIGCONT to 6260"
# <- not the expected trace
ここにありますプログラム:あなたが必要な場合はsrc/trycont.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
/* number of created processes with fork
*/
#define N 5
#define printHeader() printf("n\tpid\tlog\n");
#define printMsg(i, p, str, ...) printf("%d\t%d\t" #str "\n", i, p, ##__VA_ARGS__)
void f(int n);
void handler(int sig);
sigset_t set;
struct sigaction action;
int main(int argc, char *argv[])
{
/* mask SIGCHLD
*/
sigemptyset(&set);
sigaddset(&set, SIGCHLD);
sigprocmask(SIG_SETMASK, &set, NULL);
/* handler will be called when SIGCHLD is sent to the process
* during the handler, SIGCHLD will be masked (sa_mask)
*/
action.sa_mask = set;
action.sa_handler = handler;
action.sa_flags = 0;
/* SIGCHLD will trigger action
*/
sigaction(SIGCHLD, &action, NULL);
/* start
*/
printHeader();
f(N);
exit(EXIT_SUCCESS);
}
void f(int n)
{
pid_t p, pc;
int myIndex;
myIndex = N - n;
p = getpid();
if (n == 0)
{
/* last child
*/
printMsg(myIndex, p, "last child - stopping");
kill(p, SIGSTOP);
printMsg(myIndex, p, "END REACHED");
exit(EXIT_SUCCESS);
}
pc = fork();
if (pc == 0)
{
/* recursion
*/
f(n - 1);
/* never reached
* because of exit
*/
}
/* father
*/
/* suspending on SIGCHLD
* need to unmask the signal
* and suspend
*/
printMsg(myIndex, p, "suspending on SIGCHLD");
sigfillset(&set);
sigdelset(&set, SIGCHLD);
sigsuspend(&set);
printMsg(myIndex, p, "got SIGCHLD");
if (n < N)
{
/* child process
* but not last
*/
printMsg(myIndex, p, "stopping");
kill(p, SIGSTOP);
printMsg(myIndex, p, "awakened - sending SIGCONT to %d", pc);
kill(pc, SIGCONT);
}
else
{
/* root process
*/
printMsg(myIndex, p, "sending SIGCONT to %d", pc);
kill(pc, SIGCONT);
}
exit(EXIT_SUCCESS);
}
void handler(int sig)
{
switch (sig)
{
case SIGCHLD:
/* when the process received SIGCHLD
* we can ignore upcoming SIGCHLD
*/
action.sa_handler = SIG_IGN;
sigaction(SIGCHLD, &action, NULL);
break;
default:
break;
}
}
ここではMakefileのです:
CC=gcc
DEFINES=-D_POSIX_C_SOURCE
STD=-std=c11 -Wall -Werror
OPTS=-O2
CFLAGS=$(STD) $(DEFINES) $(OPTS) -g
LDFLAGS=
SRC=src
OBJ=obj
BIN=bin
DIRS=$(BIN) $(OBJ)
.PHONY: mkdirs clean distclean
all: mkdirs $(BIN)/trycont
$(BIN)/%: $(OBJ)/%.o
$(CC) $(CFLAGS) $(LDFLAGS) -o [email protected] $<
$(OBJ)/%.o: $(SRC)/%.c
$(CC) $(CFLAGS) -c -o [email protected] $<
mkdirs:
- mkdir $(DIRS)
clean:
rm -vf -- $(OBJ)/*.o
distclean: clean
rm -vfr -- $(DIRS)
興味深いことに、ありがとうございます。この場合、 'SIGHUP'を扱うだけでは不十分です。' SIGCONT'は停止した各プロセスに配信され、実行を再開します。各プロセスがその子を待つことは賢明です。ありがとう@ピクロウ。 – friedrich