【linux 信号学习九】阻塞和等待信号

阻塞等待信号

当执行一段不希望被一些信号打断的程序时,可以用下面方式

sigset_t new_set, old_set;

sigemptyset(&new_set);
sigaddset(&new_set,SIGINT);

if(-1 == sigprocmask(SIGBLOCK, &new_set, &old_set))
	exit(-1)

/* 受保护代码 */
······
/*************/

/* 恢复信号掩码 */
if(-1 == sigprocmask(SIG_SETMASK, &old_set, NULL))
  exit(-1)

pause(); /*等待信号唤醒*/

这就存在一个问题,如果SIGINT信号是在第二个sigprocmask函数之后发送到进程的(虽然这种情况很少),这就回出现立即执行SIGINT的回掉函数,但是pause()函数却还在等待被阻塞的信号的到来。这就和代码原来的想法不太相符。
为了避免这个问题,需要将恢复信号掩码和pause()挂起进程这两个动作封装成一个原子操作,这就是sigsuspend()函数。

阻塞信号

sigsuspend()

函数原形

#include <signal.h>

int sigsuspend(const sigset_t *mask);

参数

mask:指向一个信号集合

返回值

始终返回-1, 并设置errno。通常为EINTR,表示被信号中断,
失败:将error设置为EFAULT

sigsuspend函数会将mask信号集替换进程的信号掩码,然后挂起进程,直到捕获到信号被唤醒(如果捕获的是mask中的信号,则不会被唤醒,继续挂起)、并从信号处理函数返回,一旦从信号处理函数返回,sigsuspend()会将进程的信号掩码恢复成调用前的值。
sigsuspend()函数相当于是不可中断(原子操作)的方式执行一下操作:

sigprocmask(SIG_SETMASK, &mask, &old_mask);
pause();
sigprocmask(SIG_SETMASK, &old_mask, NULL);

正点原子示例

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

static void sig_handler(int sig)
{
 printf("执行信号处理函数...\n");
}

int main(void)
{
 struct sigaction sig = {0};
 sigset_t new_mask, old_mask, wait_mask;
 
 /* 信号集初始化 */
 sigemptyset(&new_mask);
 sigaddset(&new_mask, SIGINT);
 sigemptyset(&wait_mask);
 
 /* 注册信号处理函数 */
 sig.sa_handler = sig_handler;
 sig.sa_flags = 0;
 if (-1 == sigaction(SIGINT, &sig, NULL))
	 exit(-1);
	 
 /* 向信号掩码中添加信号 */
 if (-1 == sigprocmask(SIG_BLOCK, &new_mask, &old_mask))
 	exit(-1);
 	
 /* 执行保护代码段 */
 puts("执行保护代码段");
 /******************/
 
 /* 挂起、等待信号唤醒 */
 if (-1 != sigsuspend(&wait_mask))
 	exit(-1);
 	
 /* 恢复信号掩码 */
 if (-1 == sigprocmask(SIG_SETMASK, &old_mask, NULL))
 	exit(-1);
 	
 exit(0);
}

在上述代码中,我们希望执行受保护代码段时不被 SIGINT 中断信号打断,所以在执行保护代码段之前将 SIGINT 信号添加到进程的信号掩码中,执行完受保护的代码段之后,调用sigsuspend()挂起进程,等待被信号唤醒,被唤醒之后再解除 SIGINT 信号的阻塞状态

等待信号

sigpending

作用:获取正在等待处理的信号的集合
如果进程在执行信号处理函数期间接收到了处在信号掩码中的成员,内核会将其阻塞,将该信号添加到进程等待信号集(等待被处理,处于等待状态的信号)中,可以使用sigpending函数获取正在等待的信号集。

函数原形

#include <signal.h>

int sigpending(sigset_t *set)

函数参数

set:获取到的等待信号集

** 返回值**

成功:0
失败:-1,设置errno

正点原子示例

/* 定义信号集 */
sigset_t sig_set;

/* 将信号集初始化为空 */
sigemptyset(&sig_set);

/* 获取当前处于等待状态的信号 */
sigpending(&sig_set);

/* 判断 SIGINT 信号是否处于等待状态 */
if (1 == sigismember(&sig_set, SIGINT))
	puts("SIGINT 信号处于等待状态");
else if (!sigismember(&sig_set, SIGINT))
	puts("SIGINT 信号未处于等待状态");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值