C++ SIGTERM的信号处理程序面临问题

C++ SIGTERM的信号处理程序面临问题,c++,c,linux,C++,C,Linux,我的应用程序已经配置了一个SIGTERM处理程序。 例: 我想在关机前做一些处理,但我无法更改现有的信号处理程序。 为了进行处理,我放置了一个这样的钩子 将我的处理程序配置为 signal(SIGTERM, &mySignalHandler); mySignalHandler在完成处理后调用signalHandler,使系统即使在挂接之后也不受影响 现在,考虑到mySignalHandler将被调用的事实,它在kill$pid一次时工作。 但如果我做两次或更多次信号处理程序被调用。据我

我的应用程序已经配置了一个
SIGTERM
处理程序。 例:

我想在关机前做一些处理,但我无法更改现有的信号处理程序。 为了进行处理,我放置了一个这样的钩子 将我的处理程序配置为

signal(SIGTERM, &mySignalHandler);
mySignalHandler
在完成处理后调用
signalHandler
,使系统即使在挂接之后也不受影响

现在,考虑到
mySignalHandler
将被调用的事实,它在
kill$pid
一次时工作。 但如果我做两次或更多次<代码>信号处理程序被调用。据我所知,在这种情况下应执行
SIG_DFL

任何人都知道原因

我正在使用“Red Hat Enterprise Linux AS发行版4(Nahant更新8)”

[编辑]:测试程序面临的奇怪行为

#undef _GNU_SOURCE
using namespace std;

volatile sig_atomic_t signalHandlerVar_ = false;
volatile sig_atomic_t signalHandlerSecondVar_ = false;

extern "C" void signalHandler(int)
{
    signalHandlerVar_ = true;
}

extern "C" void signalHandlerSecond(int value)
{
    signalHandlerSecondVar_ = true;
}

void* threadFunc(void*)
{
    while(1)
    {
        if(signalHandlerVar_)
        {
            cout<<"signalHandler_ "<<signalHandlerVar_<<endl;
            signalHandlerVar_ = false;
        }

        if(signalHandlerSecondVar_)
        {
            cout<<"signalHandlerSecond_ "<<signalHandlerSecondVar_<<endl;
            signalHandlerSecondVar_ = false;
        }
    }

    return NULL;
}

int main()
{
    ::signal(SIGTERM, &signalHandler);
    ::signal(SIGTERM, &signalHandlerSecond);
    pthread_t thread;

    if(pthread_create(&thread, NULL, &threadFunc, NULL))
    {
        cout<<"pthread create failed"<<endl;
        return 1;
    }
    pthread_join(thread, NULL);
}
未定义GNU源代码
使用名称空间std;
易失性sig_原子信号handlervar_uu=false;
易失性sig_原子信号处理器SecondVar_u=false;
外部“C”无效信号处理器(int)
{
signalHandlerVar=真;
}
外部“C”无效信号句柄秒(int值)
{
signalHandlerSecondVar=真;
}
void*threadFunc(void*)
{
而(1)
{
if(信号处理程序)
{

cout在函数mySignalHandler()的末尾,必须再次调用signal():

第一次(代码中的任何位置):

然后在您的函数中:

void mySignalHandler() {
    //your code here

    signal(SIGTERM, &mySignalHandler);
}
这样,下次捕获SIGTERM时,程序将进入mySignalHandler()中

希望对您有所帮助。

来自

说明

signal()的行为因UNIX版本而异,并且 不同版本的Linux历史上有所不同。请避免 使用:改为使用sigaction(2)。请参阅下面的可移植性。

如果信号信号被传递到进程,那么 发生以下情况:
-…
-…
-如果配置设置为函数,则首先 处置被重置为SIG_DFL,或信号被阻塞(请参阅 然后使用参数调用处理程序 signum.If处理程序的调用导致信号 阻塞,则信号从 处理程序

在Linux上,这取决于你如何编译你的源代码。由于你的程序没有从任何后续的
kill
中中止,我怀疑它使用了BSD语义,如后面的可移植性部分所述

Linux上的情况如下:

  * The kernel's signal() system call provides System V semantics.

  * By default, in glibc 2 and later, the signal() wrapper function
     does not invoke the kernel system call.  Instead, it calls
     sigaction(2) using flags that supply BSD semantics.  This default
     behavior is provided as long as the _BSD_SOURCE feature test macro
     is defined.  By default, _BSD_SOURCE is defined; it is also
     implicitly defined if one defines _GNU_SOURCE, and can of course be
     explicitly defined.

    On glibc 2 and later, if the _BSD_SOURCE feature test macro is not
     defined, then signal() provides System V semantics.  (The default
     implicit definition of _BSD_SOURCE is not provided if one invokes
     gcc(1) in one of its standard modes (-std=xxx or -ansi) or defines
     various other feature test macros such as _POSIX_SOURCE,
     _XOPEN_SOURCE, or _SVID_SOURCE; see feature_test_macros(7).)

要强制系统V行为,您需要定义
\u POSIX\u SOURCE
\u XOPEN\u SOURCE
\u SVID\u SOURCE
中的一个,例如

gcc -D_SVID_SOURCE -Wall -g -pthread test.c
但是,这似乎不适用于g++

g++ -D_SVID_SOURCE -Wall -g -pthread test.cpp
您仍然可以获得BSD行为。添加
-v

g++ -v -D_SVID_SOURCE -Wall -g -pthread test.cpp
揭示

/usr/lib/gcc/x86_64-linux-gnu/4.6/cc1plus-quiet-v-imultilib-imultiarch x86_64-linux-gnu-D_gnu SOURCE-D_可重入-D_SVID_SOURCE test.cpp-quiet-dumpbase test.cpp-mtune=generic-march=x86-64-auxbase a-g-Wall-version-fstack protector-o/tmp/cc3MpiO2.s

在使用gcc编译时,它不存在。 您可以使用附加的
-U\U GNU\U源来抑制此操作

g++ -U_GNU_SOURCE -D_SVID_SOURCE -Wall -g -pthread test.cpp

最后,这给了我们System V行为,这意味着信号处理程序在第一次信号传递后被重置为
SIG_DFL

说重置为SIG_DFL是最初的Unix行为。在Linux上,它要么具有BSD行为(如果
\u BSD_SOURCE
)要么具有System V行为(如果源代码被编译为严格的标准)。如果您使用的是
-std=cXX
而不是
-std=gnuXX
进行编译,那么也许您可以尝试使用GNU功能进行编译,或者定义
\u BSD\u SOURCE
。确实应该使用sigaction来实现这一点,谢谢。希望您可以尝试这项工作。但是,如果已将signalHandler分配给SIG\u DFL,那么为什么要调用它呢这就是我想知道的。内核是否做任何簿记。“库重置信号,以便在同一信号再次出现时执行默认操作”。因此,不应该对signalHandler进行校准。它给我的印象是,在处理后,它会将SIG_DFL设置为我之前配置的。那么,内核是否会进行此类簿记。内核不进行任何簿记。它每个信号只存储一个信号处理程序。
signal
返回以前的信号处理程序。您的引用描述了系统tem V行为。这不是Linux所做的,除非您通过执行
\undef\u BSD\u SOURCE
或使用
-std=…
明确请求。请您自己尝试,并使用System V语义编译您的程序。然后您将看到您引用的行为。edidt使用Sysytem V semantic尝试了这篇文章,现在面临一些奇怪的问题D_SOURCE
没有明确定义,而是通过
\u GNU_SOURCE
隐式定义的,因此本例中的手册页不正确。请参阅更新的答案。
g++ -v -D_SVID_SOURCE -Wall -g -pthread test.cpp
g++ -U_GNU_SOURCE -D_SVID_SOURCE -Wall -g -pthread test.cpp