Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C Linux:信号处理程序的执行可以被抢占吗?_C_Linux_Signals_Interrupt Handling - Fatal编程技术网

C Linux:信号处理程序的执行可以被抢占吗?

C Linux:信号处理程序的执行可以被抢占吗?,c,linux,signals,interrupt-handling,C,Linux,Signals,Interrupt Handling,我遇到了以下存储errno变量的信号处理程序代码,这样它就不会影响主线程的errno处理 void myhandler(int signo) { int esaved; esaved = errno; write(STDOUT_FILENO, "Got a signal\n", 13); errno = esaved; } 但这真的能达到目的吗?如果在write()之后和还原errno之前,另一个线程检查共享errno变量,会发生什么情况?由于争用条件,该线程是

我遇到了以下存储errno变量的信号处理程序代码,这样它就不会影响主线程的errno处理

void myhandler(int signo)
{
    int esaved;
    esaved = errno;
    write(STDOUT_FILENO, "Got a signal\n", 13);
    errno = esaved;
}
但这真的能达到目的吗?如果在write()之后和还原errno之前,另一个线程检查共享errno变量,会发生什么情况?由于争用条件,该线程是否会得到错误的errno值

或者一个信号处理程序相对于一个线程/进程自动执行,这样一旦信号处理程序执行,内核就不会在信号处理程序完成之前调度线程了

换句话说,一旦启动,信号处理程序执行时是否不会被以下中断:

 - 1) Scheduler (process/threads),  or  
 - 2) Other signals,  or
 - 3) Hardware interrupt handlers  ?

变量
errno
是特定于线程的-或者更准确地说,在线程环境中是线程本地值或每线程值-因此在此线程中对
errno
所做的操作不会影响其他线程中的
errno

代码保存和还原
errno
的目的是隐藏
write()
系统调用在
myhandler()
中设置的任何错误。但是,如果
write()
失败,它可能会将
errno
设置为某个新值-它不会为零,但这就是您所能说的-但是您询问的代码会在调用
write()
后从调用
write()
之前恢复该值,因此,发生写入的事实是“不可见的”,即它不会影响此线程的
errno

信号处理器功能本身可能会被未被其响应信号的信号掩码阻止的信号中断。也可以重新安排。硬件中断也可能发生,但代码将很难注意到这些影响


在Linux上,您可能会发现定义宏的
/usr/include/bits/errno.h
(包含在比此处所示更多的
#ifdef
代码中):


在Linux上,
errno
是一个宏,它扩展为一个函数调用,返回一个可修改的左值,该左值对于每个线程都是不同的

请查看:

ISO C标准将errno定义为类型为的可修改左值 int,并且不能显式声明;errno可能是一个宏。厄尔诺是 线程本地;在一个线程中设置它不会影响它在任何线程中的值 其他线程

但是,实际上,在执行信号处理程序的过程中可以再次触发信号(如果您使用了
signal()
而不是
sigaction()
,这取决于您的环境;这些不一致性是建议改为使用
sigaction()
的原因),或者另一个信号可以中断处理程序的执行。这就是为什么通常在设置信号处理程序时,通过在信号处理程序执行期间将其添加到信号掩码,使其阻塞信号。这可以防止信号处理程序中断自身(在某些情况下,可以防止无限循环)

参考资料:

  • sa_mask
    可传递到以下位置的组件:

    sa_mask指定了一个应被阻止的信号掩码(即,添加到 调用信号处理程序的线程的信号掩码) 在执行信号处理程序期间。此外,信号 除非使用SA_NODEFER标志,否则处理程序将被阻止

  • :

    signal()的唯一可移植用途是将信号的配置设置为 信号灯或信号灯。使用signal()建立 信号处理程序因系统而异(POSIX.1明确允许这样做) 变异)请勿将其用于此目的。

    POSIX.1通过指定sigaction(2)解决了可移植性混乱问题,它 在调用信号处理程序时提供语义的显式控制 援引;使用该接口而不是signal()

    [……]此外,快速传递同样的信号可能会 导致处理程序的递归调用


信号处理程序确实可以被另一个信号中断(假设它与最初调用处理程序的信号不同)

您的处理程序仍然可以被另一种信号的传递中断。为了避免这种情况,您可以使用传递给sigaction的action结构的sa_mask成员来明确指定在信号处理程序运行时应该阻止哪些信号。这些信号是对调用处理程序的信号以及通常被进程阻止的任何其他信号的补充。请参阅处理程序的阻塞

当处理程序返回时,阻塞信号集将恢复为处理程序运行之前的值。因此,在处理程序内部使用sigprocmask只会影响处理程序本身执行期间可以到达的信号,而不会影响处理程序返回后可以到达的信号


即使指令
++
也不是原子指令。也不要在侧信号处理程序中使用
write()
函数。在side signal Handler中,信号处理程序中有OK函数(请参阅),并且
write()
是异步信号安全的。POSIX比C标准自由得多。不,信号处理程序不会阻止其他线程运行。这包括执行自己的信号处理程序。
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