十_信号12 - sigsuspend() 设置信号集状态 与 挂起 的原子操作

NAME
       sigsuspend, rt_sigsuspend - wait for a signal


SYNOPSIS
       #include <signal.h>

       int sigsuspend(const sigset_t *mask);

功能:以下三步为原子操作

第一步:设置当前进程信号集状态为 目标信号集状态mask,并保存进程旧的信号集状态为 oldmask

第二步:马上进入等待信号阶段

第三步:收到信号唤醒后 设置当前进程信号集状态为 旧的信号集状态oldmask。


实验1,用pause()实现,打印一行*后 ,停止等待信号 驱动程序继续跑

pause()休眠 等待信号唤醒,CTRL+C 唤醒程序执行打印下一行

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


void sig_handler(int s)
{
	write(1,"!",1);
}

int main()
{
	int i,j;
	sigset_t set,saveset;

	signal(SIGINT,sig_handler);
	
	sigemptyset(&set); 
	sigaddset(&set,SIGINT); 

	
	sigprocmask(SIG_UNBLOCK,&set,&saveset);

	for(j=0;j < 1000;j++)
	{

		sigprocmask(SIG_BLOCK,&set,NULL); 
		for(i=0 ; i<5 ; i++) 
		{
			write(1,"*",1);
			sleep(1);
		}	
		write(1,"\n",1);
		sigprocmask(SIG_UNBLOCK,&set,NULL); 
 pause();
	}

	sigprocmask(SIG_SETMASK,&saveset,NULL);

	exit(0);
}



mhr@ubuntu:~/Desktop/xitongbiancheng/test$ ./a.out 
*****
^C!*****
^C!**^C***
!

问题:
程序确实可以在打印一行后 暂定,等待 SIGINT 后再 打印下一行*。
但是,发现,如果在当前行打印途中 发送 SIGINT信号,不会驱动程序打印下一行数据,这是因为

sigprocmask(SIG_UNBLOCK,&set,NULL); pause()
这两个函数中间,当解除信号阻塞之后,还没来得及执行pause(),就把 SIGINT信号响应掉了,所以信号就作用不到 pause(),即不会唤醒进程,程序响应 SIGINT信号之后,打印!再执行到 pause()。 我们知道,程序在运行当中 可以理解为 时时刻刻都在被中断,时间片一直在反复的耗尽,也就是反复 进入内核态等待调度,再继续执行程序,所以此时 刚刚好从内核态切换回用户态,发现SIGINT信号,于是马上响应信号动作。我们的初衷是 执行完解除阻塞后,马上pause()挂起,最后SIGINT信号作用到 pause()上,打印下一行 ,
所以 这个问题的原因就是 sigprocmask(SIG_UNBLOCK,&set,NULL) 与 pause() 这两个操作组合 是非原子操作,是不原子的。

修改:用 sigsuspend()实现

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


void sig_handler(int s)
{
	write(1,"!",1);
}

int main()
{
	int i,j;
	sigset_t set,saveset,oset;

	signal(SIGINT,sig_handler);
	
	sigemptyset(&set); 
	sigaddset(&set,SIGINT); 

	
	sigprocmask(SIG_UNBLOCK,&set,&saveset);

	sigprocmask(SIG_BLOCK,&set,&oset); 
	for(j=0;j < 1000;j++)
	{

		
		for(i=0 ; i<5 ; i++) 
		{
			write(1,"*",1);
			sleep(1);
		}	
		write(1,"\n",1);
		
		sigsuspend(&oset);
	}

	sigprocmask(SIG_SETMASK,&saveset,NULL);

	exit(0);
}


mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/signal/test$ 
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/signal/test$ 
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/signal/test$ gcc sigsuspend.c 
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/signal/test$ ./a.out 
*****
^C!*****
^C!**^C*^C^C**
!*****
^C!**^\Quit (core dumped)
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/signal/test$ 

可以实现目标功能。


在这里插入图片描述

内部实现:
1 保存当前进程 当前信号屏蔽字
2 设置当前进程的信号屏蔽字为 sigmask
3 与 上一步原子的执行 pause 使进休眠
4 当进程被唤醒时,进程从 sigsuspend() 返回,被唤醒,停止休眠,并将当前进程的信号屏蔽字 还原为第一步中的屏蔽字。

在这里插入图片描述
在这里插入图片描述
void pr_mask(const char *str)//打印当前被堵塞的信号

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Linux老A

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值