代码之家  ›  专栏  ›  技术社区  ›  friedrich

SIGSTOP/SIGCONT POSIX行为

  •  3
  • friedrich  · 技术社区  · 8 年前

    SIGSTOP SIGCONT 特别地。 这是我写的一个测试程序。这个想法是创建一个N+1的链 过程(包括主过程)。每个人都要等孩子停下来,然后停下来 停止。

    f 函数递归地创建流程链。每个 进程在 SIGCHLD 与最后一个信号不同的信号 将收到 西格尔德 发出信号,然后它可以在转弯时停止。什么时候 主进程接收 西格尔德 进程处于停止状态,因此它发送 西格康特 向its发出信号 小孩每个进程发送 西格康特 给自己的孩子,然后离开,分开 从刚刚离开的最后一个孩子。

    我试图澄清:删除了返回代码测试并编写了一些 评论。

    执行程序时,一切似乎都正常,但 西格康特 链条一些进程被唤醒,但不是所有进程都被唤醒。查看 运行程序(例如使用ps)一切看起来都很好:否 阻塞进程。我真的不明白这有什么不对

    这是一个示例跟踪。正如您所看到的,“分叉链”运行良好,进程挂起 西格尔德 西格尔德 因为每个进程都会停止自己。当主进程收到 西格尔德 它发送 西格康特 它的孩子被唤醒,然后 西格康特

    $ ./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 $@ $<
    
    $(OBJ)/%.o: $(SRC)/%.c
        $(CC) $(CFLAGS) -c -o $@ $<
    
    mkdirs:
        - mkdir $(DIRS)
    
    clean:
        rm -vf -- $(OBJ)/*.o
    
    distclean: clean
        rm -vfr -- $(DIRS)
    
    1 回复  |  直到 8 年前
        1
  •  4
  •   pilcrow    8 年前

    一些(或全部?)当第一个进程终止时,您的所有子进程都会因系统生成的SIGHUP而死亡。

    这是 expected POSIX behavior 在某些情况下。

    过程组组长 ,其后代是该组的成员。当该领导终止时,流程组为 孤儿 当系统检测到一个新的孤立进程组,其中任何成员都被停止时,进程组的每个成员都被发送一个SIGHUP,然后是SIGCONT。

    确切地说,哪些后代仍然停滞不前(甚至只是兴高采烈地向他们前进) exit() )是一场计时赛。在我的系统中,领队终止得如此之快,以至于所有的后代都无法打印任何内容。