c - 在子进程中使用信号

标签 c operating-system

我想创建一个简单的程序,它使用 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) 向子进程添加一个信号捕获函数,并创建一个打印所需结果的处理函数,但它仍然无法正常工作。有什么想法吗?

最佳答案

如果您发送 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. 在 parent 中阻止信号,以便 child 从信号被阻止开始
  2. 在 child 中安装处理程序
  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; 
}

关于c - 在子进程中使用信号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55190460/

相关文章:

c - 为什么在将复数从 fortran 传递到 c 时不能 printf

c - 当输入超过 8 位值时,以下程序 "Counting consecutive 1' s 的二进制 no"显示不同的 ans?

c - 从 32 位机器发送数据包并在 64 位机器上接收

c - 用于读取的原子 block 与 ARM SysTicks

linux - Debian 操作系统内核版本差异 : 3. 16.51-3 vs 3.16.51-3+deb8u1

c - :protocol pseudo-header in http2? 在静态表中的索引号是多少

php - 使用 PHP 检测 Mac OS 版本

c - 我为 C 编程作业创建的 system.h 文件是否有可能给我的操作系统带来问题?

operating-system - 限制虚拟内存的因素有哪些?

c - fork() 在这个 C 程序中是如何工作的?