关于sigsuspend返回多个信号的问题

大多数关于sigsuspend等的例子,都是先屏蔽信号,然后调用sigsuspend获取一个信号,然后处理,然后继续等待下个信号。实际上,手册上没有说《Unix环境高级编程》也没有说,若同时有多个信号,sigsuspend会一次取完。

基于sigsuspend每次只收取一个信号的假设,设计了一个系统,后来发现SIGCHLD和MYSIGIO(SIGRTMIN+1)在sigsuspend之后同时蹦出来了!

#0  MasterProcess::SignalHandlerFunction (signo=35) at process_model.cpp:265
#1  0x0000000000403c61 in Process::SignalHandlerStatic (signo=35) at process_model.cpp:54
#2  0x000000000040704b in SignalHandler::Handler (signo=35) at signal_handler.cpp:51
#3  <signal handler called>
#4  SignalHandler::Handler (signo=0) at signal_handler.cpp:50// 第一次是收到SIGCHLD(17),但马上被新信号35中断了。这个时候signo还没有初始化。
#5  <signal handler called>
#6  0x0000003723432d2a in sigsuspend () from /lib64/libc.so.6

在信号35处理完后,处理17这个信号:

#0  MasterProcess::SignalHandlerFunction (signo=17) at process_model.cpp:265
#1  0x0000000000403c61 in Process::SignalHandlerStatic (signo=17) at process_model.cpp:54
#2  0x000000000040704b in SignalHandler::Handler (signo=17) at signal_handler.cpp:51//调用完信号35的处理函数,又调用17的处理函数。
#3  <signal handler called>
#4  0x0000003723432d2a in sigsuspend () from /lib64/libc.so.6

这台服务器信息是:

Linux dev6 2.6.32-71.el6.x86_64 #1 SMP Fri May 20 03:51:51 BST 2011 x86_64 x86_64 x86_64 GNU/Linux
CentOS Linux release 6.0 (Final)

引用另外一篇文章的分析:http://blog.csdn.net/muge0913/article/details/7334840

                                       

所以明显,sigsuspend不可能让两个信号都蹦出来。最初也这么假设,后来却发现拿到了两个信号。


在RHEL上看到也是两个信号一起蹦出来,不过显示35然后是17(有时候是和上面一样,所以是随机的),堆栈如下:

#0  Process::SignalHandlerStatic (signo=17) at process_model.cpp:52
#1  0x0804debe in SignalHandler::Handler (signo=17) at signal_handler.cpp:51 //马上又来了SIGCHLD
#2  <signal handler called>
#3  SignalHandler::Handler (signo=35) at signal_handler.cpp:50 // 先收到SIGRTMIN+1
#4  <signal handler called>
#5  0xffffe410 in __kernel_vsyscall ()
#6  0x003e9cfc in sigsuspend () from /lib/tls/libc.so.6

这台服务器信息是:
Linux CHN-DG-2-5CF 2.6.24.4 #3 SMP Fri Jul 11 13:31:27 CST 2008 i686 i686 i386 GNU/Linux
Red Hat Enterprise Linux AS release 4 (Nahant Update 5)

可见从centos 4到centos6都有这个情况。

查看sigsuspend的手册:

NAME
       sigsuspend - wait for a signal

DESCRIPTION
       sigsuspend()  temporarily replaces the signal mask of the calling process with the mask given by mask and then suspends the process until delivery of a signal whose action is to invoke a signal handler or to terminate a process.
       If the signal terminates the process, then sigsuspend() does not return.  If the signal is caught, then sigsuspend() returns after the signal handler  returns,  and the signal mask is restored to the state before the call to sigsuspend().
       It is not possible to block SIGKILL or SIGSTOP; specifying these signals in mask, has no effect on the process’s signal mask.

NOTES
       Normally,  sigsuspend()  is  used  in conjunction with sigprocmask(2) in order to prevent delivery of a signal during the execution of a critical code section.  The caller first blocks the signals with sigprocmask(2).  When the critical code has completed, the caller then waits for the signals by calling sigsuspend()  with  the signal mask that was returned by sigprocmask(2) (in the oldset argument).

手册中的Description没有明确说会收到一个还是多个信号,但在Notes中,写的是“wait for the signals”说明是可能多个信号都到来。原子的意思是不会漏掉信号。

看下面的原型,程序进入临界区域后sleep 10秒,然后向程序发送3个信号,sigsuspend一次就收到了三个信号:

// mpserver6 —— prototype for the multiple signals in queue for sigsuspend
#include <stdlib.h>
#include <iostream>
using namespace std;

#include <unistd.h>
#include <signal.h>
#include <sys/ioctl.h>

bool global_terminate = false;

void signal_handler(int signo){
    cout << "[signal_handler] get a signal: " << signo << endl;
    
    switch(signo){
        case SIGINT:
        case SIGHUP:
        case SIGTERM:
        case SIGQUIT:
            global_terminate = true;
            break;
        case SIGCHLD:
        case SIGALRM:
        case SIGIO:
        case SIGUSR1:
        case SIGUSR2:
            break;
    }
}

int main(int argc, char** argv){
    // register signal handler
    signal(SIGCHLD, signal_handler);
    signal(SIGINT, signal_handler);
    signal(SIGQUIT, signal_handler);
    signal(SIGUSR1, signal_handler);
    signal(SIGUSR2, signal_handler);
    cout << "[master] register signal handler success!" << endl;
    
    // block signals to enter critical regions.
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGCHLD);
    sigaddset(&set, SIGINT);
    sigaddset(&set, SIGQUIT);
    sigaddset(&set, SIGUSR1);
    sigaddset(&set, SIGUSR2);
    if(sigprocmask(SIG_BLOCK, &set, NULL) == -1){
        cout << "[main] sigprocmask block signal failed!" << endl;
        exit(0);
    }
    cout << "[main] sigprocmask block signal success!" << endl;
    
    // critical regions.
    cout <<"[main] use command to send multiple signals: " << endl 
        << "kill -SIGCHLD " << getpid()  << endl
        << "kill -SIGUSR2 " << getpid() << endl
        << "kill -SIGUSR1 " << getpid() << endl;
    sleep(10);
    cout << "[main][master] use sigsuspend to accept signals." << endl;
    
    // start to accept singals.
    sigset_t empty_set;
    sigemptyset(&empty_set);
    for(;;){
        sigsuspend(&empty_set);
        cout << "[main] process a signal" << endl;
        
        if(global_terminate){
            exit(0);
        }
    }
    
    return 0;
}

运行结果如下:

[signal_handler] get a signal: 17
[signal_handler] get a signal: 12
[signal_handler] get a signal: 10
[signal_handler] get a signal: 3
[main] process a signal

 其实sigsuspend拿到一个还是多个信号都无所谓,只要没有做错误的假设,c和oo的方式都有解,有限状态就是已知的和确定的。 

你可能感兴趣的:(c,Google,Signal)