c - 在子进程中使用信号
问题描述
我想创建一个简单的程序,它使用 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);
}
要消除竞争条件,您需要
- 阻塞父级中的信号,以便子级以阻塞的信号开始
- 在孩子中安装处理程序
- 解锁信号并
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;
}
推荐阅读
- python - 如何重置用户的权限 [Discord.py]
- java - Spring找不到网址
- c# - C#可以将字符串格式存储在变量中吗?
- yaml - 无效的请求 - 无法识别的类型:应用 kubectl 时的字符串
- amazon-web-services - 是否可以在 lightsail 实例上禁用源/目标检查?
- pattern-matching - 如何在 ML 中对 ADT 进行模式匹配
- php - PHP/HTML:智能页面缓存(仅在后退和前进按钮单击时使用缓存的 HTML,但强制页面在直接链接上重新加载)
- android - 私有属性的 Android 风格属性命名约定中 * 的意义
- android - “Google 将分享您的姓名、电子邮件地址...”即使应用程序未请求这些字段,Google 登录帐户选择屏幕中的消息
- reactjs - 我不知道如何在 react redux todo app 中使用 visibilityFilters