前期说到sigsuspend的几种具体应用:
1 保护临界区不被信号中断
#include "apue.h"/*************************************************************************
> File Name: sigsuspeng.c
> Author: lifeng
> Mail: lifeng0070@gmail.com
> Created Time: 2014骞?0鏈?4鏃?鏄熸湡浜?14鏃?0鍒?1绉?
************************************************************************/
#include
#include
#include
#include
static void pr_mask_info(const char *str);
static void sig_int(int);
static void pr_mask(const char *str)
{
sigset_t sigset;
int save_errno;
save_errno = errno;
if(sigprocmask(0, NULL, &sigset) < 0)
{
printf("sigprocmask error");
exit(1);
}
printf("%s", str);
if(sigismember(&sigset, SIGINT))
printf("SIGINT ");
if(sigismember(&sigset, SIGQUIT))
printf("SIGQUIT ");
if(sigismember(&sigset, SIGUSR1))
printf("SIGUSR1 ");
if(sigismember(&sigset, SIGALRM))
printf("SIGALRM ");
printf("\n");
errno = save_errno;
}
int main(void)
{
sigset_t newmask, oldmask, waitmask;
pr_mask("program start:");//打印系统默认屏蔽情况,通过执行情况发现默认不屏蔽任何信号
if(signal(SIGINT, sig_int) == SIG_ERR)
{
printf("signal(SIGINT) error");
exit(1);
}
sigemptyset(&waitmask);
sigaddset(&waitmask, SIGUSR1);
sigemptyset(&newmask);
sigaddset(&newmask, SIGINT);
if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
{
printf("SIG_BLOCK error");
exit(1);
}
/* critical region ode */
pr_mask("in critical region:");//newmask里的信号被屏蔽,SIGINT
if(sigsuspend(&waitmask) != -1)//如果执行没有信号的话,会停在这里,一直等待信号,waitmask屏蔽SIGUSR1,一旦有信号,执行完信号处理程序,才会往下执行,在我们的执行结构里,可以看到,一共屏蔽了2个信号,SIGINT和SIGUSR1
{
printf("sigsuspend error");
exit(1);
}
pr_mask("after return from sigsuspend:");//这里我们再看看执行完suspend的情况,屏蔽信号又只剩下SIGINT
if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
{
printf("SIG_SETMASK error");
exit(1);
}
pr_mask("program exit:");
exit(0);
}
static void sig_int(int signo)
{
pr_mask("\nin sig_int:");
}
执行情况:
整个sigsuspend的执行,设置新的信号屏蔽字,或者解除原来的屏蔽字,然后挂起,是原子的,捕捉到信号以后,再恢复到设置以前的状态
整个过程都是原子的,中间不会丢失信号。是可靠地。
2 等待一个全局变量被设置
这种情况是等待一个信号处理程序设置一个全局变量。下面的例子用于捕捉中断信号和退出信号,但是希望仅当退出信号处理程序时,才唤醒主进程。
#include
#include
#include
volatile sig_atomic_t quitflag;
/*
当把声明为该类型会保证该变量在使用或赋值时, 无论是在32位还是64位的机器上都能保证操作是原子的, 它会根据机器的类型自动适应。这个类型是定义在signal.h文件中。
*/
static void sig_int(int signo)
{
if(signo == SIGINT)
printf("\ninterrupt\n");
else if(signo == SIGQUIT)
quitflag = 1;//等待这个全局变量
}
int main(void)
{
sigset_t newmask, oldmask, zeromask;
if(signal(SIGINT, sig_int) == SIG_ERR)
{
printf("signal(SIGINT) error");
exit(1);
}
if(signal(SIGQUIT, sig_int) == SIG_ERR)
{
printf("signal(SIGQUIT) error");
exit(1);
}
sigemptyset(&zeromask);
sigemptyset(&newmask);
sigaddset(&newmask, SIGQUIT);
if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)//屏蔽SIGQUIT信号
{
printf("SIG_BLOCK error");
exit(1);
}
while(quitflag == 0)
{
sigsuspend(&zeromask);//sigsuspend解开所有屏蔽信号,然后等待quitflag变成1,然后才往下执行,否则在这里循环
printf("quitflag = %d\n", quitflag);
}
quitflag = 0;
if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
{
printf("SIG_SETMASK error");
exit(1);
}
exit(0);
}
由显示结果可以看出,sigsuspend放开屏蔽信号,按下“ctrl+C”,进入中断,但是不设置quitflag,直到按下“ctrl+\”,quitflag置1,才往下执行。
在单进程程序当中,主进程和中断共享变量,这不失为一种好办法。
3 父子进程通信,关于这个只有几个函数。在此不做记录。
另外重点说下sigaction函数:
int sigaction(int signo, const struct sigaction *restrict act, struct *restrictoact);
这个函数用来修改或者检查与指定信号相关联的处理动作,其中,参数signo是要检测或者修改其具体动作的信号编号,若act指针非空,
则要修改其动作,若oact非空,则系统由oact指针返回该信号的上一个动作。其中的结构体如下:
struct sigaction{
void (*sa_handler)(int);
sigset_t sa_mask;
int sa_flag;
void (*sa_sigaction)(int, siginfo_t *, void *);
};
关于这个函数可以这样理解:如果sa_handler字段有效,即这个字段是一个有效信号捕捉地址,则sa_mask字段信号集是这样的
在调用该捕捉函数前,这一信号集要加到进程的信号屏蔽字中,仅当从信号捕捉函数返回时再将进程的信号屏蔽字恢复到原来状态
这样,在信号处理函数调用时,就能阻塞某些信号,即在执行信号处理程序时,系统新建立的信号能被屏蔽,保证了在信号处理过程当中,
如果同一种信号再次发生,那么它会被阻塞到前一个新红处理完毕。例如:
int main(void)
{
int i = 0;
struct sigaction act, oldact;
act.sa_handler = show_handler;
...
sigaddset(&act.sa_mask, SIGQUIT);
....
sigaction(SIGINT, &act, &oldact);
while(1) {
sleep(1);
printf("sleeping %d\n", i);
i++;
}
}
上面函数设置SIGINT捕捉函数,在从SIGINT信号处理函数返回以前,把SIGQUIT信号屏蔽,从信号处理函数返回以后,恢复原来的信号屏蔽字。
这样即使在信号处理过程当中产生SIGQUIT信号,在接触屏蔽以后,信号SIGQUIT也能递达而不丢失。
阅读(1946) | 评论(0) | 转发(0) |