Linux系统编程50 信号- 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/parallel/signal/test$ ./a.out 
*****
^C!*****
^C!*****
^C!****^C*
!^\Quit (core dumped)
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/signal/test$ 

问题:
程序确实可以在打印一行后 暂定,等待 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$ 

可以实现目标功能。

猜你喜欢

转载自blog.csdn.net/LinuxArmbiggod/article/details/114124505