首页 > 解决方案 > 在子进程中使用信号

问题描述

我想创建一个简单的程序,它使用 fork 并创建一个使用 pause 正在等待的子进程。我希望这个子进程在它从父进程获得特定信号后启动。我写的代码:

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

int main() {
    pid_t c = fork();
    if (c == 0) {
        pause();
        printf("signal was given");
    }
    if (c > 0)
        kill(c, SIGINT);

    return 0;
}

我认为 kill 给带有 pid c(child) 的进程一个特定的信号,我认为 pause 只是等待一个信号来取消暂停该进程。但是,在这种情况下,运行此程序没有任何结果。我还尝试使用signal(SIGINT, handler)并创建一个打印所需结果的处理程序函数向孩子添加一个信号捕获函数,但它仍然无法正常工作。有任何想法吗?

标签: coperating-system

解决方案


如果您将SIGINT默认处置是终止进程的 发送到既不阻止也不处理它​​的进程,则该进程将终止。

如果您希望信号中断像 一样的阻塞调用pause(),它需要有一个处理程序。

但是简单地安装一个处理程序会引入竞争条件:

if (c == 0 ){
    //< if the signal arrives here the child dies
    signal(SIGINT, handler);
    //< if the signal arrives here then nothing happens except the handler is run
    pause(); //< if the handler arrives here then pause gets interrupted
    printf("signal was given\n");
    exit(0);
}

要消除竞争条件,您需要

  1. 阻塞父级中的信号,以便子级以阻塞的信号开始
  2. 在孩子中安装处理程序
  3. 解锁信号并pause()在一个原子步骤中

要实现 3. 一步,您需要sigsuspend()代替pause().

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

void handler(int Sig){}

int main()
{
    sigset_t sigint, oldmask; sigemptyset(&sigint); sigaddset(&sigint, SIGINT);
    sigprocmask(SIG_BLOCK, &sigint, &oldmask);

    pid_t c=fork();
    if(0>c) return perror(0),1;
    if (c==0){
        signal(SIGINT, handler);
        sigdelset(&oldmask,SIGINT); /*in (the unlikely) case the process started with SIGINT blocked*/
        sigsuspend(&oldmask);
        printf("signal was given\n");
        exit(0);
    }
    kill(c,SIGINT);
    wait(0);
    return 0; 
}

或者,您可以完全使用sigwait()和放弃对处理程序的需求:

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

int main()
{
    sigset_t sigint, oldmask; sigemptyset(&sigint); sigaddset(&sigint, SIGINT);
    sigprocmask(SIG_BLOCK, &sigint, &oldmask);

    pid_t c=fork();
    if(0>c) return perror(0),1;
    if (c==0){
        int sig; sigwait(&sigint,&sig);
        printf("signal was given\n");
        exit(0);
    }
    kill(c,SIGINT);
    wait(0);
    return 0; 
}

推荐阅读