using select() with pipe - 这就是我正在做的事情,现在我需要抓住SIGTERM
。我该怎么做?当select()
返回错误(< 0)时,我是否必须这样做?
答案 0 :(得分:16)
首先,如果没有抓住,SIGTERM
将终止您的流程,而select()
将不返回。因此,您必须为SIGTERM
安装信号处理程序。使用sigaction()
。
但是,SIGTERM
信号可能会在select()
处阻止 的线程时到达。如果您的进程主要是在文件描述符上休眠,那么这将是一种罕见的情况,但否则会发生。这意味着您的信号处理程序必须执行某些操作以通知主例程中断,即设置一些标志变量(类型为sig_atomic_t
),或者您必须保证SIGTERM
仅在进程正在select()
上暂停。
我将采用后一种方法,因为它更简单,虽然不太灵活(见帖子的结尾)。
因此,您在调用SIGTERM
之前阻止select()
,并在函数返回后立即重新锁定它,以便您的进程仅在select()
内睡眠时接收信号。但请注意,这实际上会产生竞争条件。如果信号在解除阻塞之后到达,但在调用select()
之前,系统调用尚未被调用,因此它不会返回-1
。如果信号在select()
成功返回后到达,但在重新阻止之前,您也丢失了信号。
因此,您必须使用pselect()
。它以原子方式select()
进行阻塞/解除阻塞。
首先,在进入SIGTERM
循环之前使用sigprocmask()
阻止pselect()
。之后,只需使用pselect()
返回的原始掩码调用sigprocmask()
。这样,您就可以保证只有在select()
上睡觉时才会中断您的流程。
总结:
SIGTERM
安装处理程序(无效); pselect()
循环之前,使用SIGTERM
阻止sigprocmask()
; pselect()
; sigprocmask()
pselect()
循环中,现在您可以安全地检查pselect()
是否返回-1
并且 errno
是EINTR
。< / LI>
醇>
请注意,如果在pselect()
成功返回后,您执行了大量工作,则在响应SIGTERM
时可能会遇到更长的延迟(因为该流程必须执行所有处理并返回{{ 1}}在实际处理信号之前)。如果这是一个问题,您必须在信号处理程序中使用标志变量,以便您可以在代码中的许多特定点检查此变量。但是,使用标志变量并不能消除竞争条件,也不会消除pselect()
的需要。
请记住:每当您需要等待一些文件描述符或来传递信号时,必须使用{{1} }(或pselect()
,对于支持它的系统。)
编辑:没有什么比代码示例更能说明用法了。
pselect()
答案 1 :(得分:4)
答案部分在于您指出的Q&amp; A中的一条评论;
&GT;中断将导致select()返回-1,并将errno设置为EINTR
那是;对于捕获的任何中断(信号),select将返回,并且errno将被设置为EINTR。
现在,如果您特别想要捕获SIGTERM,那么您需要通过调用signal
来设置它,就像这样;
signal(SIGTERM,yourcatchfunction);
你的catch函数应该被定义为
void yourcatchfunction(int signaleNumber) { .... }
总而言之,您已经设置了一个信号处理程序yourcatchfunction
,并且您的程序当前处于等待IO的select()
调用中 - 当信号到达时,您的catch函数将被调用,当您返回时从那里,select调用将返回,并将errno设置为EINTR。
但请注意,SIGTERM可以随时发生,因此当发生时,不可能会处于选择调用中,在这种情况下,您将永远不会看到EINTR但只能定期调用yourcatchfunction
因此,使用err和errno EINTR返回的select()只是为了你可以采取非阻塞动作 - 它不会捕获信号。
答案 2 :(得分:1)
您可以循环调用select()
。这称为重新启动系统调用。这是一些伪C。
int retval = -1;
int select_errno = 0;
do {
retval = select(...);
if (retval < 0)
{
/* Cache the value of errno in case a system call is later
* added prior to the loop guard (i.e., the while expression). */
select_errno = errno;
}
/* Other system calls might be added here. These could change the
* value of errno, losing track of the error during the select(),
* again this is the reason we cached the value. (E.g, you might call
* a log method which calls gettimeofday().) */
/* Automatically restart the system call if it was interrupted by
* a signal -- with a while loop. */
} while ((retval < 0) && (select_errno == EINTR));
if (retval < 0) {
/* Handle other errors here. See select man page. */
} else {
/* Successful invocation of select(). */
}