linux的信号异步通知信号

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

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种信号;

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>

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

};

这个就是内容 标准的内容 使用这个结构体两种方式 第一种是将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个标志位
信号一般是用于高并发服务器 所以在服务器内部常常会被使用 信号的作用非常大

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值