我想使用 sigaction(),但我遇到了问题
I want to use sigaction(), but I've a problem
我想制作一个程序
如果进程收到 SIGQUIT,打印一些消息并终止进程。
这是我的代码,
void signal_handler(int num)
{
printf(Received SIGQUIT\n");
kill(getpid(), SIGINT);
}
int main()
{
struct sigaction sig;
sig.sa_handler = signal_handler;
sigemptyset(&sig.sa_mask);
sig.sa_flags = 0;
sigaction(SIGQUIT, &sig, NULL);
for(;;) {
printf("Input SIGQUIT : ");
}
return 0;
}
我的预期结果是
输入 SIGQUIT: ^\ 收到 SIGQUIT
并终止进程,
但实际结果是
enter image description here
在收到 SIGQUIT
之前未打印消息 "Input SIGQUIT:"
我想知道为什么..
首先:您引用的代码无法编译。请post验证码;
这会增加您获得答案的机会。
我可以自由地将您的问题重新表述为
如何优雅地终止程序?
我知道,不应该重新表述问题。但为了理智,我有
传播 异步信号传递是错误的说法
那是 UNIX 诞生时
发明。请继续阅读以下内容
对原因和一些替代方案的一些解释。但首先,
TL;DR: 不使用异步信号传递。很难得到
异步信号传递对-有很多陷阱(感谢
@Shawn 征求意见)。而是同步等待信号
到达。这是它的样子,
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
int main(void)
{
int error;
// setup set of signals that are meant to terminate us
sigset_t termination_signals;
sigemptyset(&termination_signals);
sigaddset(&termination_signals, SIGTERM);
sigaddset(&termination_signals, SIGINT);
sigaddset(&termination_signals, SIGQUIT);
// block asynchronous delivery for those
error = sigprocmask(SIG_BLOCK, &termination_signals, NULL);
if (error) {
perror("sigprocmask(SIGTERM|SIGINT|SIGQUIT)");
exit(1);
}
// wait for one of these signals to arrive. EINTR handling is
// always good to have in larger programs. for example, libraries
// might make use of signals in their own weird way - thereby
// disturbing their users most impolitely by interrupting every
// operation they synchronously wait for.
while (1) {
int sig;
error = sigwait(&termination_signals, &sig);
if (error && errno == EINTR) {
perror("sigwait");
continue;
}
printf("received termination signal %d\n", sig);
break;
}
return 0;
}
异步信号传递
信号是穷人的通知。这就像扔整数
过程中的值(具有预定义的含义)。本来,像他们
正在发明 UNIX,他们必须想出一个通知机制
在进程之间使用。他们这样做的方式类似于
当时流行的通知机制:中断。 (虽然这可能
听起来很愤世嫉俗,我敢打赌我离得不远。)
在你真正决定走那条路之前要问自己的问题:
- 我真的知道我需要它吗?
- 有什么后果?
- 有其他选择吗?
虽然我无法帮助 1.,但这里有一些关于 2. 和 3. 的信息
异步信号处理的后果
异步信号传递导致您的程序进入
某种形式的并行性:信号处理程序 中断 正常
程序流程。这种中断可能不会发生在时间
节目是为他们准备的。
中断机制与您可能知道的相当
最高级别的多线程。这两者的共同点
可能是,“如果你不小心你就死了,但你可能
甚至不知道。竞争条件。
异步信号传递与
多线程,除了增加死亡率。
好像这还不够,还有中断系统的概念
调用.
基本原理是这样的(取自肯·汤普森和丹尼斯·里奇之间的假设对话,就在大纪元之前),
Q: now we have defined a notification mechnism between processes
(asynchronous signal delivery), and jumped through hoops to call a
user supplied function to handle delivery.
Now what if the target process sleeps? Waits for something to
happen? Timer? Data from a serial port maybe?
A: let's wake him up!
这样做的效果是阻止系统调用(比如从
TCP 连接 - 这些当时还没有 - ,或者来自
串行端口)被中断。当您从套接字读取时,或者
否则阻塞直到某些事件发生,调用 return 非零,
使用全局 errno
变量(早期的另一个神器
七十年代)被设置为 EINTR
.
我仍然不清楚当
目标进程有多个线程,每个线程阻塞
某物。我希望 每个 这样的阻塞调用都会被中断。
不幸的是行为不一致,甚至在 Linuxen 上也不一致,让
单独其他我很久没用过的 UNIXen。我不是一个
标准律师,但仅此一项就让我 运行 远离这个奥术
机制。
也就是说,如果您还没有运行离开,请通知您自己
关于确切的定义。在我看来,最好的起点是
是阅读 man 7 signal
手册
页。不容易
虽然阅读,但准确。
接下来,要知道在中断服务程序中可以做什么,err
信号处理函数,通读 man 7 signal-safety
手动
页。你会
看到,例如,以下 none 是安全的:
- 没有
printf()
。你在信号处理程序中使用它,所以请
不。 printf()
的 None 个兄弟姐妹,这样的 fprintf()
是安全的
任何一个。 None 个 <stdio.h>
。
<pthread.h>
不安全。您不能修改线程安全数据
结构,因为你会无意中锁定互斥量或信号(双关语
预期的)条件变量,或使用其他一些线程
机制.
备选方案
同步等待信号。我上面引用的代码就是这样做的。
事件驱动编程。以下是Linux具体的
其基础是某种形式的事件循环。图形用户界面工具包
以这种方式工作,所以如果你的代码是这样一个更大的画面的一部分,你
可以将 基于文件描述符的信号通知 挂钩到某物中
那已经存在了。
事件源本质上是文件描述符。套接字以这种方式工作。见 man
signalfd
如何创建一个文件描述符来吐出信号通知。
事件循环在其基础上使用以下系统调用之一
(从最简单到最强大的顺序),
自管技巧。参见here;这通常在您的程序基于事件时使用,但您不能使用上面的 Linux-特定 signalfd()
。
我想制作一个程序 如果进程收到 SIGQUIT,打印一些消息并终止进程。 这是我的代码,
void signal_handler(int num)
{
printf(Received SIGQUIT\n");
kill(getpid(), SIGINT);
}
int main()
{
struct sigaction sig;
sig.sa_handler = signal_handler;
sigemptyset(&sig.sa_mask);
sig.sa_flags = 0;
sigaction(SIGQUIT, &sig, NULL);
for(;;) {
printf("Input SIGQUIT : ");
}
return 0;
}
我的预期结果是
输入 SIGQUIT: ^\ 收到 SIGQUIT
并终止进程,
但实际结果是
enter image description here
在收到 SIGQUIT
之前未打印消息 "Input SIGQUIT:"我想知道为什么..
首先:您引用的代码无法编译。请post验证码; 这会增加您获得答案的机会。
我可以自由地将您的问题重新表述为
如何优雅地终止程序?
我知道,不应该重新表述问题。但为了理智,我有 传播 异步信号传递是错误的说法 那是 UNIX 诞生时 发明。请继续阅读以下内容 对原因和一些替代方案的一些解释。但首先,
TL;DR: 不使用异步信号传递。很难得到 异步信号传递对-有很多陷阱(感谢 @Shawn 征求意见)。而是同步等待信号 到达。这是它的样子,
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
int main(void)
{
int error;
// setup set of signals that are meant to terminate us
sigset_t termination_signals;
sigemptyset(&termination_signals);
sigaddset(&termination_signals, SIGTERM);
sigaddset(&termination_signals, SIGINT);
sigaddset(&termination_signals, SIGQUIT);
// block asynchronous delivery for those
error = sigprocmask(SIG_BLOCK, &termination_signals, NULL);
if (error) {
perror("sigprocmask(SIGTERM|SIGINT|SIGQUIT)");
exit(1);
}
// wait for one of these signals to arrive. EINTR handling is
// always good to have in larger programs. for example, libraries
// might make use of signals in their own weird way - thereby
// disturbing their users most impolitely by interrupting every
// operation they synchronously wait for.
while (1) {
int sig;
error = sigwait(&termination_signals, &sig);
if (error && errno == EINTR) {
perror("sigwait");
continue;
}
printf("received termination signal %d\n", sig);
break;
}
return 0;
}
异步信号传递
信号是穷人的通知。这就像扔整数 过程中的值(具有预定义的含义)。本来,像他们 正在发明 UNIX,他们必须想出一个通知机制 在进程之间使用。他们这样做的方式类似于 当时流行的通知机制:中断。 (虽然这可能 听起来很愤世嫉俗,我敢打赌我离得不远。)
在你真正决定走那条路之前要问自己的问题:
- 我真的知道我需要它吗?
- 有什么后果?
- 有其他选择吗?
虽然我无法帮助 1.,但这里有一些关于 2. 和 3. 的信息
异步信号处理的后果
异步信号传递导致您的程序进入 某种形式的并行性:信号处理程序 中断 正常 程序流程。这种中断可能不会发生在时间 节目是为他们准备的。
中断机制与您可能知道的相当 最高级别的多线程。这两者的共同点 可能是,“如果你不小心你就死了,但你可能 甚至不知道。竞争条件。
异步信号传递与 多线程,除了增加死亡率。
好像这还不够,还有中断系统的概念 调用.
基本原理是这样的(取自肯·汤普森和丹尼斯·里奇之间的假设对话,就在大纪元之前),
Q: now we have defined a notification mechnism between processes (asynchronous signal delivery), and jumped through hoops to call a user supplied function to handle delivery.
Now what if the target process sleeps? Waits for something to happen? Timer? Data from a serial port maybe?
A: let's wake him up!
这样做的效果是阻止系统调用(比如从
TCP 连接 - 这些当时还没有 - ,或者来自
串行端口)被中断。当您从套接字读取时,或者
否则阻塞直到某些事件发生,调用 return 非零,
使用全局 errno
变量(早期的另一个神器
七十年代)被设置为 EINTR
.
我仍然不清楚当 目标进程有多个线程,每个线程阻塞 某物。我希望 每个 这样的阻塞调用都会被中断。 不幸的是行为不一致,甚至在 Linuxen 上也不一致,让 单独其他我很久没用过的 UNIXen。我不是一个 标准律师,但仅此一项就让我 运行 远离这个奥术 机制。
也就是说,如果您还没有运行离开,请通知您自己
关于确切的定义。在我看来,最好的起点是
是阅读 man 7 signal
手册
页。不容易
虽然阅读,但准确。
接下来,要知道在中断服务程序中可以做什么,err
信号处理函数,通读 man 7 signal-safety
手动
页。你会
看到,例如,以下 none 是安全的:
- 没有
printf()
。你在信号处理程序中使用它,所以请 不。printf()
的 None 个兄弟姐妹,这样的fprintf()
是安全的 任何一个。 None 个<stdio.h>
。 <pthread.h>
不安全。您不能修改线程安全数据 结构,因为你会无意中锁定互斥量或信号(双关语 预期的)条件变量,或使用其他一些线程 机制.
备选方案
同步等待信号。我上面引用的代码就是这样做的。
事件驱动编程。以下是Linux具体的
其基础是某种形式的事件循环。图形用户界面工具包 以这种方式工作,所以如果你的代码是这样一个更大的画面的一部分,你 可以将 基于文件描述符的信号通知 挂钩到某物中 那已经存在了。
事件源本质上是文件描述符。套接字以这种方式工作。见 man
signalfd
如何创建一个文件描述符来吐出信号通知。
事件循环在其基础上使用以下系统调用之一 (从最简单到最强大的顺序),
自管技巧。参见here;这通常在您的程序基于事件时使用,但您不能使用上面的 Linux-特定 signalfd()
。