信号量在在Linux中有着举足轻重的地位,Linux中一些异常错误也由信号量触发,另外信号量也可以用来做进程间的通信,比如Nignx中master-worker模式的进程通信就是使用信号量。
信号量的自定义处理
typedef void (*sig_t) (int)
sig_t signal(int sig, sig_t func)
sig
:自定义处理的信号量
func
:信号量的处理函数
信号量的屏蔽
int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oldset)
how有三种模式
- SIG_BLOCK :屏蔽的信号量集合为
set
- SIG_UNBLOCK : 解出屏蔽的信号量集合为
set
- SIG_SETMASK : 设置的信号量集合为
set
特别注意信号量屏蔽阶段,被屏蔽的信号量如果多次触发,在该信号量解出屏蔽时也只会再触发一次。
信号量挂起
int sigsuspend(const sigset_t *sigmask)
该函数会阻塞当前执行的进程,直到信号集中的信号触发
特别注意,如果某个信号已经被设置成BLOCK
模式的时候,再sisuspend
操作的信号集中如果有该信号,那么信号的BLOCK
模式将被取消,触发就执行相应的处理。
例子
下面用一个例子说明3个函数的使用方法
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
static int quit = 0;
static void Signal_handler(int s)
{
printf("Catch a signal:%d\n", s);
if( s == SIGQUIT)
{
printf("quit!\n");
quit = 1;
}
}
void Init_signal()
{
struct sigaction act;
act.sa_handler = Signal_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, NULL);
sigaction(SIGQUIT, &act, NULL);
sigaction(SIGUSR1, &act, NULL);
sigaction(SIGUSR2, &act, NULL);
sigaction(SIGBUS, &act, NULL);
}
void Block_signal()
{
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGCHLD);
sigaddset(&set, SIGINT);
sigaddset(&set, SIGUSR1);
if(sigprocmask(SIG_BLOCK, &set, NULL) < 0)
{
printf("sigprocmask error\n");
}
}
int main(int argc, char *argv[])
{
Init_signal();
Block_signal();
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGCHLD);
sigaddset(&set, SIGINT);
sigaddset(&set, SIGUSR1);
printf("%d\n", time(NULL));
while(1)
{
sigsuspend(&set);
printf("%d\n", time(NULL));
if( quit == 1)
{
break;
}
}
sigemptyset(&set);
sigsuspend(&set);
return 0;
}
假如进程号为:1571
依次执行以下操作:
kill -2 1571 //SIG_INT 信号
kill -3 1571 //SIG_QUIT 信号
执行结果如下:
1479737350
Catch a signal:3
quit!
1479737379
Catch a signal:2
总结
信号量看似简单,实则比较复杂,本文只介绍了单进程单线程的信号量使用,多线程的使用比较复杂,还需要继续学习。