Linux信号机制

Posted iamwho

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux信号机制相关的知识,希望对你有一定的参考价值。

1.信号本质


  信号是进程间通信机制中唯一的异步通信机制,在软件层次上是对中断机制的一种模拟。即信号类似软中断。

  信号和软中断的区别:

    [1]中断有优先级,而信号没有优先级。

    [2]信号处理程序是在用户态下运行的,而中断处理程序是在核心态下运行。

    [3]中断响应是及时的,而信号响应通常都有较大的时间延迟。

2.信号的种类


  信号分为可靠信号和不可靠信号。

  可靠信号:可靠信号即通过排队的方式使信号不会丢失,信号值位于SIGRTMIN和SIGRTMAX之间的信号都是可靠信号。

  不可靠信号:信号值小于SIGRTMIN的信号都是不可靠信号,即不会进行排队。

[[email protected] ~]# kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

3.信号处理


 

  信号的处理方式有三种:

    [1]忽略信号,即对信号不做任何处理,其中,有两个信号不能忽略:SIGKILL及SIGSTOP。

    [2]捕捉信号。定义信号处理函数,当信号发生时,执行相应的处理函数。

    [3]执行缺省操作,Linux对每种信号都规定了默认操作。

  信号的安装函数:signal() 和 sigaction()。

    [1]sighandler_t signal(int signum, sighandler_t handler);

    [2]int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

  这两个函数的唯一区别就是sigaction()函数的参数多了几个控制字段。

4.信号发送


  发送信号的主要函数有:kill()、raise()、 sigqueue()、alarm()、setitimer()以及abort()。

 

 

 

 

6.sigaction的使用


  sigaction函数的参数act:

struct sigaction {
	void     (*sa_handler)(int);                        //信号处理函数
	void     (*sa_sigaction)(int, siginfo_t *, void *);
	sigset_t   sa_mask;                                 //信号回调函数执行期间的信号屏蔽集
	int        sa_flags;                                //标记
	void     (*sa_restorer)(void);
};

  sa_mask表示信号回调函数执行期间的信号屏蔽集。

  sa_flags常设置为SA_RESTART:信号会导致系统调用(例如read()函数、sleep()函数)执行期间被打断,导致系统调用立刻返回失败(并且error被设置为EINTR),设置此标记后则系统调用不会立刻返回,而是在信号回调处理完成后继续系统调用流程。

  下面的代码中,在信号屏蔽集中加入了信号SIGINT,这表示在信号回调函数执行期间会阻塞信号SIGINT,知道回调函数执行完才会继续处理这个SIGINT信号。

static void signal_handler(int sig)
{
    printf("Processing SIGUSR1...\n");
    sleep(5);
    printf("sleep over\n");
}

int main(int argc, char** argv)
{
    struct sigaction act, oldact;

    act.sa_handler = signal_handler;
    sigemptyset(&act.sa_mask);
    sigaddset(&act.sa_mask, SIGINT);
    act.sa_flags = SA_RESTART;

    if(sigaction(SIGUSR1, &act, &oldact) < 0){
        perror("sigaction error");
        return 1;
    }

    while(1)
        sleep(10);

	return 0;
}

  

 

  问题1:使用signal函数时,并且使用编译选项-std=c99时,调用rt_sigaction()函数时会带上标记:SA_NODEFER|SA_RESETHAND,导致信号处理函数只能进入一次,后面再次触发信号会无效。

  问题2:下面的程序运行时,如果连续执行“kill -SIGUSR1 2068”多次时(例如5次),回调函数只执行了2次。这是因为第2次信号被阻塞了,内核的实现就是在给进程发送信号时,如果进程还有该信号等待处理,那后发的信号就什么都不做就返回了。

static void sig_fun(int sig)
{
	printf("sig fun in\n");
	sleep(5);
	printf("sig fun out\n");
}

int main()
{
	signal(SIGUSR1, sig_fun);
	while(1)
		sleep(1);

	return 0;
}

  问题3:使用signal()函数时,并且使用编译选项-std=c99,这会导致信号回调函数执行后被重置为默认处理,并且在回调函数执行期间不阻塞当前信号。所以最好用sigaction来代替signal注册信号。

 

以上是关于Linux信号机制的主要内容,如果未能解决你的问题,请参考以下文章

Linux信号机制

linux中的signal机制(转)

Linux信号(signal) 机制分析

linux信号机制分析

linux 信号机制

linux 信号机制