我遇到以下信号处理程序代码存储errnovariables,以便它不会影响主线程的errno处理。
void myhandler(int signo) { int esaved; esaved = errno; write(STDOUT_FILENO, "Got a signal\n", 13); errno = esaved; }
但是这真的有用吗? 如果另一个线程在write()之后和恢复errno之前检查共享的errnovariables,会发生什么情况? 那个线程由于竞争状态会得到错误的errno值吗?
或者一个信号处理程序相对于一个线程/进程primefaces地执行,所以一旦信号处理程序执行,内核不会安排回线程直到信号处理程序结束?
换句话说 – 一开始,一个信号处理程序执行时不会被下面的中断:
- 1) Scheduler (process/threads), or - 2) Other signals, or - 3) Hardware interrupt handlers ?
变量errno
是线程特定的,或者更准确地说,在一个线程环境中,是一个线程本地值或每个线程值 – 所以在这个线程中errno
做法不会影响其他线程中的errno
。
保存和恢复errno
的代码的目的是为了隐藏myhandler()
的write()
系统调用所设置的任何错误。 但是,如果write()
失败,它可能会将errno
为一个新的值 – 它不会是零,但是这只是你可以说的 – 但是你要求的代码在write()
调用之前恢复了值write()
在调用write()
,所以写入发生的事实是“不可见的”,因为它不会影响此线程的errno
。
信号处理函数本身可能会被信号掩码中的信号所中断,而这些信号正在响应信号。 它也可以被重新安排。 硬件中断也可能发生,但代码将很难注意到这些影响。
在Linux上,你可能会发现/usr/include/bits/errno.h
定义了宏errno
(用比这里显示的更多的#ifdef
代码包装):
extern int *__errno_location (void) __THROW __attribute__ ((__const__)); # if !defined _LIBC || defined _LIBC_REENTRANT /* When using threads, errno is a per-thread value. */ # define errno (*__errno_location ()) # endif
信号处理程序确实可以被另一个信号中断(假设它不是首先调用处理程序的信号)。
您的处理程序仍然可以通过传递另一种信号来中断。 为了避免这种情况,可以使用传递给sigaction的action结构的sa_mask成员来显式指定在信号处理程序运行时哪些信号应该被阻塞。 除了处理程序被调用的信号以外,这些信号以及通常由进程阻塞的任何其他信号。 请参阅阻止处理程序。
当处理程序返回时,被阻塞的信号集恢复到处理程序运行之前的值。 因此,在处理程序中使用sigprocmask只影响处理程序本身执行期间可能到达的信号,而不是处理程序返回时可以到达的信号。
http://www.gnu.org/software/libc/manual/html_node/Signals-in-Handler.html#Signals-in-Handler
在Linux上, errno
是一个宏,它扩展成一个函数调用,返回每个线程都不同的可修改的左值。
查看手册页 :
errno由ISO C标准定义为int类型的可修改左值,且不能被明确声明; errno可能是一个宏。 errno是线程本地的; 在一个线程中设置它不会影响其在任何其他线程中的值。
但是,实际上信号可以在信号处理程序的中间执行(如果您使用signal()
而不是sigaction()
,这取决于您的环境;这些不一致是推荐使用sigaction()
),或者另一个信号可以中断处理程序的执行。 这就是为什么当您设置信号处置时,通常在执行信号处理程序期间,通过将其添加到信号掩码中来阻止信号(对于该处理程序,在多个信号的情况下) 。 这可以防止信号处理程序自行中断(在某些情况下防止无限循环)。
参考文献:
可以传递给sigaction()
sa_mask
组件:
sa_mask指定在执行信号处理程序期间应该被阻塞的信号的掩码(即,被添加到调用信号处理程序的线程的信号掩码)。 另外, 触发处理程序的信号将被阻塞 ,除非使用了SA_NODEFER标志。
signal()
:
signal()的唯一可移植使用是将信号的处置设置为SIG_DFL或SIG_IGN。 使用signal()建立信号处理程序的语义在不同的系统中是不同的(POSIX.1明确地允许这种变化); 不要为此使用它。
POSIX.1通过指定sigaction(2)解决了可移植性问题 ,它在调用信号处理程序时提供了对语义的显式控制。 使用该接口而不是signal()。
此外,快速交付相同的信号可能会导致处理程序的递归调用。