signal linux进程,Linux捕捉信号机制之(signal,kill)、(sigaction,sigqueue)

linux下公有64个信号,kill -l 查看一下:

a16e17dfe63842480563809ee9986bdf.png

可以看到,缺少了32、33两个未知信号,从这里分界,前面31个信号是不可靠信号,后面的是可靠信号。当进程发生阻塞的时候(一下子发送很多信号),不可靠信号容易丢失。如何去验证呢?可以在2(不可靠信号)号信号和34(可靠进程)号信号屏蔽期间,不断向某个进程发送这两个信号,待解除屏蔽后,观察是否丢失。这里测试的时候,要注意一下,9-SIGKILL 19-SIGSTOP 31 32 这4个信号是不能被捕获的,遍历以下所有信号就可以发现了。

信号集

首先,讲一下信号集,顾名思义,存放信号的集合。

信号集的操作函数有以下几个,具体使用,后面再说。

554d8f3c96e79151d4518bc46a2af144.png

signal

第一种是利用signal,kill函数。

#include < signal.h>

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);

signal()有两个参数:信号编号和处理函数(sighandler_t是一个函数指针),返回值也是一个sighandler_t类型的,这里返回的是之前的信号处理函数。

信号处理函数是一个带int参数,返回值为void的函数。handler也可以是两个特殊的值:SIG_IGN 屏蔽该信号 SIG_DFL 恢复默认行为

#include < sys/types.h>

#include < signal.h>

int kill(pid_t pid, int sig);

kill()的作用是把信号sig发送给进程pid。

#include

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

功能:读取过更改进程的信号屏蔽字。

返回值:成功为0,失败为-1

参数:如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出(就是将原来的信号屏蔽字备份到oset);set是更改进程的信号屏蔽字,how指示如何修改。how的可选值如下:

2665deabf32ea9b99eddb33a6b47f302.png

代码如下:

// 3.不可靠信号的丢失

void handler(int no)

{

printf("received a signal: %d\n",no);

}

int main()

{

pid_t pid;

sigset_t set;

sigset_t oset;

int i;

sigemptyset(&set); //清空

sigaddset(&set,2); //添加2号信号

sigaddset(&set,34); //添加34号信号

for(i = 1 ; i <= 64 ; i++) //查看集合状态

{

if(sigismember(&set,i) == 1)

{

printf("1");

}

else

{

printf("0");

}

}

printf("\n");

sigprocmask(SIG_SETMASK,&set,&oset); //将这个集合设置为这个进程的阻塞信号集

//绑定信号

signal(2,handler);

signal(34,handler);

sleep(50); //在此期间,向该进程发送多次2、34号信号

sigprocmask(SIG_SETMASK,&oset,NULL);//解除绑定

while(1)

{

}

return 0;

}

在另一个终端(20s内),发送信号:

d7d56e3712a99085d6c700082b3b2757.png

结果,可以看到,不可靠信号,只收到了一次:

de11222b81ce5716680a34f095434576.png

sigaction

第二种是sigacton函数。

#include

int sigaction(int signum, const struct sigaction *act,

struct sigaction *oldact);

功能:用于改变进程接收到特定信号后的行为。

参数:signum 除了SIGKILL 和SIGSTOP(为这两个信号定义自己的处理函数,将导致信号安装错误);

第二个参数是指向结构sigaction的一个实例的指针,在结构sigaction的实例中,制定了对特定信号的处理,可以为空,进程会以缺省方式对信号处理;

old用来保存原来对信号的处理,可以为NULL。

返回值:成功为0,失败-1

sigaction结构体

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_handler和sa_sigaction都是自定义信号处理函数,同样,sa_handler有两个默认值:SIG_DFL和SIG_IGN。区别在于sa_sigaction是为实时信号而设定的(也支持非实时信号),第二个参数是指向siginfo_t结构的指针,结构中包含信号携带的数据值,第三个参数暂时没有使用(POSIX没有规范使用该指针的标准);

sa_mask是屏蔽信号集;

sa_flags有以下几个值:

a124b412cd7c891520e4596b46b88aa3.png

重点掌握2个:一个是设置为0,表示默认属性;一个是设置为SA_SIGINFO,那么此时处理函数不再使用sa_handler,而是sa_sigaction.

那么sa_sigaction的结构体参数长什么样呢?

siginfo_t {

int si_signo; /* Signal number */

int si_errno; /* An errno value */

int si_code; /* Signal code */

pid_t si_pid; /* Sending process ID */

uid_t si_uid; /* Real user ID of sending process */

int si_status; /* Exit value or signal */

clock_t si_utime; /* User time consumed */

clock_t si_stime; /* System time consumed */

sigval_t si_value; /* Signal value */

int si_int; /* POSIX.1b signal */

void *si_ptr; /* POSIX.1b signal */

void *si_addr; /* Memory location which caused fault */

天哪,肯定记不住。不需要记,用到的时候,查一下就好了。

这里掌握两个,一个是si_signum,不用说了吧,一个是si_value。这是什么?这是在发送信号时携带的一个数据,数据类是sigval,这是一个联合体。

typedef union sigval

{

int sival_int;

void *sival_ptr;

}sigval_t;

sigqueue函数

#include < signal.h>

int sigqueue(pid_t pid, int sig, const union sigval value);

sigqueue()类似于之前的kill()。是用来发送信号的,主要针对有带参的信号,与sigaction()配合使用。

第三个参数是一个联合数据结构union sigval,指定了信号传递的参数,即通常所说的4字节值。

具体代码如下:

void handler(int signo,siginfo_t *resdata,void *unknowp)

{

printf("signo=%d\n",signo);

printf("return data :%d\n",resdata->si_value.sival_int);

}

int main()

{

int i = 5;

pid_t pid = 0;

pid = fork();

if(pid == -1)

{

perror("create fork");

return -1;

}

else if(pid == 0)

{

sleep(1);

//向父进程发送带整型数据的信号

union sigval sigvalue;

sigvalue.sival_int = 111;

//发送信号

while(i--)

{

sigqueue(getppid(),2,sigvalue);

printf("send signal:2 success!\n");

sigqueue(getppid(),34,sigvalue);

printf("send signal:34 success!\n");

}

}

else

{

struct sigaction act;

//初始化sa_mask

sigemptyset(&act.sa_mask);

act.sa_sigaction=handler;

//一旦使用了sa_sigaction属性,那么必须设置sa_flags属性的值为SA_SIGINFO

act.sa_flags=SA_SIGINFO;

//注册信号

sigaction(2,&act,NULL);

sigaction(34,&act,NULL);

}

while(1)

{

}

}

运行结果:

0a81d257d7f6c9d12db3a71eddddb9d1.png

同样,可以看到2号信号只收到了1次。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值