面对SIGTERM的信号处理程序问题

时间:2014-05-22 11:06:45

标签: c++ c linux

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

Signal(SIGTERM, &signalHandler);

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

signal(SIGTERM, &mySignalHandler);

mySignalHandler稍后在进行处理后调用signalHandler即使在挂钩之后也不会影响系统。

现在,考虑到mySignalHandler将被调用的事实,它在kill $pid一次时起作用。 但如果我这样做两次或更多次。 signalHandler被调用。据我所知,在这种情况下应该执行SIG_DFL

任何人都知道原因。

我正在使用“Red Hat Enterprise Linux AS第4版(Nahant Update 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);
}

我面临的问题是,在每个kill $ pid上它调用signalHandlerSecond.as我正在使用#undef _GNU_SOURCE并尝试#undef _BSD_SOURCE.But它应该将其重置为SIG_DFL。

有人可以建议我做错了吗?

2 个答案:

答案 0 :(得分:2)

来自signal

  

<强>描述

     

signal()的行为在UNIX版本中有所不同,并且也是如此   不同版本的Linux在历史上各不相同。避免它   使用:使用sigaction(2)代替。请参阅下面的便携性   ...
  如果信号signum被传递给进程,那么其中一个   发生以下情况:
   - ......
   - ......
   - 如果处置设置为函数,则首先   处置重置为SIG_DFL,或信号被阻止(见   下面的可移植性,然后使用参数调用处理程序   正负号。如果调用处理程序导致信号   被阻止,然后信号在从...返回时被解锁   处理程序。

在Linux上,它取决于您如何编译源代码。由于您的程序没有从任何后续kill中止,我怀疑它使用BSD语义,如后面 Portability

中所述。
  

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).)

要强制执行System V行为,您需要定义_POSIX_SOURCE_XOPEN_SOURCE_SVID_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_REENTRANT -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_GNU_SOURCE

来取消此操作
g++ -U_GNU_SOURCE -D_SVID_SOURCE -Wall -g -pthread test.cpp

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

答案 1 :(得分:0)

在你的函数mySignalHandler()结束时,你必须再次调用signal():

第一次(代码中的任何地方):

signal(SIGTERM, &mySignalHandler);

然后在你的函数中:

void mySignalHandler() {
    //your code here

    signal(SIGTERM, &mySignalHandler);
}

像这样,下次捕获SIGTERM时,程序将进入mySignalHandler()

希望它对你有所帮助。