linux的信号异步通知信号

linux的异步信号通知通用的函数有以下:都在#include<asm/signal.h>库函数里面
这个sys是指的/usr/include/x86_64-linux-gnu/asm/signal.h
内部是这样定义的
typedef unsigned long sigset_t;linux

int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oldset);
第一个参数:三种屏蔽信号的模式 SIG_BLOCK表明讲第二个参数所包含的信号进行添加到当前进程的屏蔽集里面 用来阻塞对应这个集合的信号 若是这个信号集合没有屏蔽集包含的信号那么就作其余处理 能够自定义捕获处理也能够忽略
SIG_UNBLOCK:就一句話将当前进程集合里面的信号进行设置非阻塞 其实也就是被清理屏蔽的信号集
SIG_SETMASK:就是覆盖掉当前进程信号屏蔽集的屏蔽信号程序员

sigemptyset(sigset_t *set)初始化由set指定的信号集,信号集里面的全部信号被清空;

sigfillset(sigset_t *set)调用该函数后,set指向的信号集中将包含linux支持的64种信号;web

sigaddset(sigset_t *set, int signum)在set指向的信号集中加入signum信号;数组

sigdelset(sigset_t *set, int signum)在set指向的信号集中删除signum信号;服务器

sigismember(const sigset_t set, int signum)断定信号signum是否在set指向的信号集中。
  信号:
  #define SIGHUP 1
#define SIGINT 2
#define SIGQUIT 3
#define SIGILL 4
#define SIGTRAP 5
#define SIGABRT 6
#define SIGIOT 6
#define SIGBUS 7
#define SIGFPE 8
#define SIGKILL 9
#define SIGUSR1 10
#define SIGSEGV 11
#define SIGUSR2 12
#define SIGPIPE 13
#define SIGALRM 14
#define SIGTERM 15
#define SIGSTKFLT 16
#define SIGCHLD 17
#define SIGCONT 18
#define SIGSTOP 19
#define SIGTSTP 20
#define SIGTTIN 21
#define SIGTTOU 22
#define SIGURG 23
#define SIGXCPU 24
#define SIGXFSZ 25
#define SIGVTALRM 26
#define SIGPROF 27
#define SIGWINCH 28
#define SIGIO 29
#define SIGPOLL SIGIO
/

#define SIGLOST 29
/
#define SIGPWR 30
#define SIGSYS 31
/
signal 31 is no longer “unused”, but the SIGUNUSED macro remains for backwards compatibility */
#define SIGUNUSED 31并发

/* These should not be considered constants from userland. */
#define SIGRTMIN 32
#define SIGRTMAX _NSIG

内部采用和的64位的无符号长整型 支持64种信号 用bit位进行标记异步

下面说说信号的使用方式:
信号的绑定和捕获:其实信号的绑定和捕获都是一块儿进行操做的 有两种方式
sighandler_t signal(int signum, sighandler_t handler);
能够按照参数进行操做 其实就是把第一个参数(信号)和第二个参数操做函数进行绑定 通常第二个参数是void类型的函数无返回值 由于没有返回值 因此咱们聪明的程序员想到了另外一种方式 就是
#include <signal.h>ide

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

千万别把函数sigaction和struct sigaction搞混了 这个虽然名字同样 可是一个是函数 一个是结构体
用法呢就是第一个参数是信号 第二个是struct sigaction结构体 第三个呢就是保存当前的信号处理方式也就是旧的处理信号方式
通常咱们用这个sigcation函数进行处信号是经过第二个参数结构体 内部进行注册函数的方式进行绑定
可是注册处理信号函数有两种方式 先给你们看一下结构体内容
struct sigaction
{
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags; //会影响信号接受特殊标志
void (*sa_restorer)(void);svg

};函数

这个就是内容 标准的内容 使用这个结构体两种方式 第一种是将sa_flags赋值0 而后这个时候信号的默认处理模块就是sa_handler 若是sa_flags赋值SA_SIGINFO 那么就采用sa_sigaction 进行处理信号这个类型的处理模块具备的好处就是能够进行返回值 不像上一个sa_handler同样不灵活

举个例子
//test for sigsuspend
#include<signal.h>
#include<stdlib.h>
#include<errno.h>
#include<stdio.h>
void print_sig(sigset_t *p)
{
int i = 1;
for(;i < 32;++i){
if(sigismember(p,i)){
printf(“1”);
}else{
printf(“0”);
}
}
printf("\n");
}

void pr_mask(char *str)
{
sigset_t sigset01;
int errno_save;
errno_save=errno;
//获取当前的信号屏蔽集合
if(sigprocmask(0,NULL,&sigset01)<0)
perror(“sigprocmask erro!”);

printf("%s\n",str);  
//判断屏蔽信号集合中是否存在中断信号
if(sigismember(&sigset01,SIGINT))    
	printf("SIGINT\n");
//判断屏蔽信号集合中是否存在退出程序信号
if(sigismember(&sigset01,SIGQUIT))   
	printf("SIGQUIT\n");
//判断屏蔽信号集合是否存在
if(sigismember(&sigset01,SIGUSR1))   
	printf("SIGUSR1\n");
if(sigismember(&sigset01,SIGALRM))   
	printf("SIGALRM\n");
errno=errno_save;

}
static void sig_int(int signo)
{
printf(“signo=%d\n”,signo);
pr_mask("\ntest :in sig_int\n");
}

int main(void)
{
//设置信号屏蔽集
sigset_t newmask,oldmask,waitmask;
sigset_t p;

pr_mask("program start:");
//绑信号处理
if(signal(SIGINT,sig_int)==SIG_ERR)
  perror("signal(SIGINT) error!!\n");

if(signal(SIGUSR1,sig_int)==SIG_ERR)
	perror("signal(SIGUSR1) error");
//信号清空初始化
sigemptyset(&waitmask);
sigemptyset(&p);
//信号清空初始化 本质上清空sigset_t 结构体内部的long数组
//添加信号SIGUSR1 
sigaddset(&waitmask,SIGUSR1);
//信号清空
sigemptyset(&newmask);
sigaddset(&newmask,SIGALRM);
//添加信号SIGINT/
sigaddset(&newmask,SIGINT);
//添加设置当前进程的信号屏蔽字
        sigpending(&p);
    print_sig(&p);

if(sigprocmask(SIG_BLOCK,&newmask,&oldmask)<0)
  perror("SIG_BLOCK  erro!!\n");
          sigpending(&p);
	      print_sig(&p);


pr_mask("in critical region:");

if(sigsuspend(&waitmask)!=-1)
  perror("sigsuspend  erro!!\n");
 
sigpending(&p);
print_sig(&p);

pr_mask("after return from sigsuspend:");

if(sigprocmask(SIG_SETMASK,&oldmask,NULL)<0)
  perror("SIG-SETMASK erro!!\n");
           sigpending(&p);
    print_sig(&p);

while(1);
pr_mask("\nprogram exit:\n");
exit(0);

}

刚开始的结果是
这个例子 hfy@hfy-virtual-machine:~/Desktop/0410Linux异步通知机制/code-today$ ./sigsuspend_test
program start:
0000000000000000000000000000000
0000000000000000000000000000000
in critical region:
SIGINT
SIGALRM

刚开始我什么操做都没有作 自动回产生这样的结果显示

接着我发送一个SIGINT信号
hfy@hfy-virtual-machine:~/Desktop/0410Linux异步通知机制/code-today$ ./sigsuspend_test
program start:
0000000000000000000000000000000
0000000000000000000000000000000
in critical region:
SIGINT
SIGALRM
^Csigno=2

test :in sig_int

SIGINT
SIGUSR1
0000000000000000000000000000000
after return from sigsuspend:
SIGINT
SIGALRM
0000000000000000000000000000000
这个例子容易混淆的地方是sigpending 和sigismember 两个系统调用 前者是进行返回未决信号 什么是未决信号 就是传送到当前进程的信号被阻塞了 没有处理这个叫作未决信号 sigprocmask(0,0,od);获取当前进程的信号屏蔽集 也就是当前进程的sigset_t 保存的屏蔽集 获取未决信号和获取当前进程存在的信号屏蔽集是两个概念 不要搞混了
我记得内核里面的删除屏蔽集的信号处理是void sigdelset(sigset_t * set,int signo)
{

*set&=~(1<<(signo-1)); } 下面的具体函数就不写了 我写一下关键之处 好比添加 *set|=(1<<(signo-1)); 好比清空是 #define sigemptyset(sigset_t *set) (*set=0); 还有一些就不写了 具体从这几个例子能够看出来 这些信号屏蔽集 其实就利用信号位进行标记 只不过标记的时候要进行移位操做 好比我添加一个SININT 中断信号 他的内核实现是#define SIGINT 2 那么内核对于屏蔽信号存储的结果就是0000…00010 中间省去不少0 总共是64个标志位 信号通常是用于高并发服务器 因此在服务器内部经常会被使用 信号的做用很是大