问题描述
- 这是我在做什么,现在我需要搭上 SIGTERM
上。我该怎么办呢?我必须这样做时,选择()
返回错误(小于0)?
using select() with pipe - this is what I am doing and now I need to catch SIGTERM
on that. how can I do it? Do I have to do it when select()
returns error ( < 0 ) ?
推荐答案
首先, SIGTERM
将杀您的过程中,如果没有抓住,而选择()
将的不的回报。因此,您必须安装 SIGTERM
的信号处理程序。做,使用的sigaction()
。
First, SIGTERM
will kill your process if not caught, and select()
will not return. Thus, you must install a signal handler for SIGTERM
. Do that using sigaction()
.
但是, SIGTERM
信号可在瞬间到达您的线程的不的挡在选择()
。这将是一个罕见的情况,如果你的过程主要是在文件描述符睡觉,但它可以否则发生。这意味着,无论你的信号处理程序必须做一些事情来通知中断的主程序,即设置一些标志变量(类型为 sig_atomic_t
),或者你必须保证 SIGTERM
时,过程是睡在只提供选择()
。
However, the SIGTERM
signal can arrive at a moment where your thread is not blocked at select()
. It would be a rare condition, if your process is mostly sleeping on the file descriptors, but it can otherwise happen. This means that either your signal handler must do something to inform the main routine of the interruption, namely, setting some flag variable (of type sig_atomic_t
), or you must guarantee that SIGTERM
is only delivered when the process is sleeping on select()
.
我将与后者的做法去,因为它的简单,尽管不那么灵活(详见后结束)。
I'll go with the latter approach, since it's simpler, albeit less flexible (see end of the post).
所以,你挡住 SIGTERM
只是打电话之前选择()
,并reblock它在函数返回之后马上,让你的过程中只接收而在睡觉的信号选择()
。但是请注意,这实际上创建了一个竞争状态。如果刚过疏通,但之前选择()
被调用时,系统调用将还没有被调用,因此它不会返回<$ C $信号到达C> 1 。如果刚过信号到达选择()
成功返回,但只是重块之前,你也失去了信号。
So, you block SIGTERM
just before calling select()
, and reblock it right away after the function returns, so that your process only receives the signal while sleeping inside select()
. But note that this actually creates a race condition. If the signal arrives just after the unblock, but just before select()
is called, the system call will not have been called yet and thus it will not return -1
. If the signal arrives just after select()
returns successfully, but just before the re-block, you have also lost the signal.
因此,你必须使用 PSELECT()
为。它确实阻断/解锁周围选择()
原子。
Thus, you must use pselect()
for that. It does the blocking/unblocking around select()
atomically.
首先,块 SIGTERM
使用 sigprocmask()执行
进入 PSELECT前()
循环。在此之后,只需调用 PSELECT()
与返回原来的面具sigprocmask()执行
。这样,你保证你的程序将只在睡觉选择中断()
。
First, block SIGTERM
using sigprocmask()
before entering the pselect()
loop. After that, just call pselect()
with the original mask returned by sigprocmask()
. This way you guarantee your process will only be interrupted while sleeping on select()
.
在总结:
- 安装了
SIGTERM
的处理程序(即什么都不做); - 进入使用
PSELECT()
环,块SIGTERM
sigprocmask()之前
; - 呼叫
PSELECT()
含)由返回旧的信号掩码sigprocmask(
; - 在
PSELECT()
循环,现在你可以放心地检查PSELECT()
是否返回1
的和的错误号
是EINTR
。
- Install a handler for
SIGTERM
(that does nothing); - Before entering the
pselect()
loop, blockSIGTERM
usingsigprocmask()
; - Call
pselect()
with the old signal mask returned bysigprocmask()
; - Inside the
pselect()
loop, now you can check safely whetherpselect()
returned-1
anderrno
isEINTR
.
请注意,如果在 PSELECT()
返回成功,你做了很多的工作,响应时可能会遇到更大的延迟 SIGTERM
(因为这个过程必须尽一切处理和实际处理信号之前返回 PSELECT()
)。如果这是一个问题,你必须使用一个标志变量的信号处理程序中,这样就可以在你的code在一些具体的点检查这个变量。使用标志变量并没有消除竞争条件,并且不排除在必要 PSELECT()
,虽然
Please note that if, after pselect()
returns successfully, you do a lot of work, you may experience bigger latency when responding to SIGTERM
(since the process must do all processing and return to pselect()
before actually processing the signal). If this is a problem, you must use a flag variable inside the signal handler, so that you can check for this variable in a number of specific points in your code. Using a flag variable does not eliminate the race condition and does not eliminate the need for pselect()
, though.
记住:当你需要等待一些文件描述符或的一个信号的传送,你的必须的使用 PSELECT()
(或 ppoll()
,为支持它的系统)。
Remember: whenever you need to wait on some file descriptors or for the delivery of a signal, you must use pselect()
(or ppoll()
, for the systems that support it).
编辑:无非是code例子更好地说明用法
nothing better than a code example to illustrate the usage.
#define _POSIX_C_SOURCE 200809L
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>
#include <unistd.h>
// Signal handler to catch SIGTERM.
void sigterm(int signo) {
(void)signo;
}
int main(void) {
// Install the signal handler for SIGTERM.
struct sigaction s;
s.sa_handler = sigterm;
sigemptyset(&s.sa_mask);
s.sa_flags = 0;
sigaction(SIGTERM, &s, NULL);
// Block SIGTERM.
sigset_t sigset, oldset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGTERM);
sigprocmask(SIG_BLOCK, &sigset, &oldset);
// Enter the pselect() loop, using the original mask as argument.
fd_set set;
FD_ZERO(&set);
FD_SET(0, &set);
while (pselect(1, &set, NULL, NULL, NULL, &oldset) >= 0) {
// Do some processing. Note that the process will not be
// interrupted while inside this loop.
sleep(5);
}
// See why pselect() has failed.
if (errno == EINTR)
puts("Interrupted by SIGTERM.");
else
perror("pselect()");
return EXIT_SUCCESS;
}
这篇关于醒目而从管道读取与选择信号()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!