#include <stdio.h>
#include <signal.h>
void checkset();
void func();
void main()
信号(signal)是一种进程间通信机制,它给应用程序提供一种异步的软件中断,使应用
程序有机会接受其他程序活终端发送的命令(即信号)。
应用程序收到信号后,有三种处理方式:忽略,默认,或捕捉。进程收到一个信号后,
会检查对该信号的处理机制。如果是SIG_IGN,就忽略该信号;如果是SIG_DFT,则会采用系
统默认的处理动作,通常是终止进程或忽略该信号;如果给该信号指定了一个处理函数
(捕捉),则会中断当前进程正在执行的任务,转而去执行该信号的处理函数,返回后再继续
执行被中断的任务。
sigsuspend
一、信号集(sigset_t)
信号集表示一个信号集合,可以将其传递给sigprocmask函数,指定阻塞哪些信号。下
面是操作信号集的函数:
#include <signal.h>
int sigemptyset(sigset_t *set);//清空信号集
int sigfillset(sigset_t *set);//填充信号集
int sigaddset(sigset_t *set, int signo);//向信号集中加入指定信号signo
int sigdelset(sigset_t *set, int signo);//从信号集中移除指定信号signo
All four return: 0 if OK, -1 on error
int sigismember(const sigset_t *set, int signo);//测试signo是否在信号集中
Returns: 1 if true, 0 if false, -1 on error
二、sigprocmask函数
sigprocmask函数可以用来设置进程的信号掩码,即指定哪些信号需要被阻塞;它也可
以用来获取当前进程的信号掩码。
int sigprocmask ( int how, const struct * set, struct * oset );
how指定sigprocmask的操作类型:
SIG_BLOCK 指定将set中的信号加入当前的信号掩码中,即添加需要阻塞的信号;
SIG_UNBLOCK 指定将set中的信号从当前的信号掩码中移除,即解除阻塞信号;
SIG_SETMASK 设置当前的信号掩码为set;
如果oset不为null,当前进程的信号掩码通过oset返回。
如果set为null,则当前信号掩码通过oset返回,how将被忽略。
如果调用sigprocmask时,有当前被挂起的信号被解除阻塞,则在sigprocmask返回之前
至少有一个信号被传递给进程。sigprocmask是为单线程的进程而设计的。
三、sigpending函数
int sigpending ( sigset_t *set );
通过set返回当前被阻塞而挂起的信号。
四、sigsuspend函数
if(sigsuspend(&zeroset)!= -1)
{
printf("sigsuspenderror\n");
exit(0);
}
sigsuspend 用实参 sigmask 指定的信号集代替调用进程的信号屏蔽,
然后挂起该进程直到某个不属于 sigmask 成员的信号到达为止。
此信号的动作要么是执行信号句柄,要么是终止该进程。
如果信号终止进程,则 suspend 函数不返回。
如果信号的动作是执行信号句柄,则在信号句柄返回后,sigsuspend 函数返回,并使
进程的信号屏蔽恢复到 sigsuspend 调用之前的值。
sigsuspend的整个原子操作过程为:
(1) 设置新的mask阻塞当前进程;
(2) 收到信号,调用该进程设置的信号处理函数;
(3) 待信号处理函数返回后,恢复原先mask;
(4) sigsuspend返回。
清晰且可靠的等待信号到达的方法是先阻塞该信号(防止临界区重入,也就是在次期间
有另外一个该信号到达),然后使用sigsuspend 放开此信号并等待句柄设置信号到达标志
。如下所示, 等待 SIGUSR1 信号到来:
sigemptyset(&zeromask);
sigaddset(&newmask, SIGUSR1);
......
sigprocmask(SIG_BLOCK, &newmask, NULL);
while(flag)
sigsuspend(&zeromask);
flag = 0;
......
sigprocmask(SIG_UNBLOCK, &newmask, NULL);
列子:
#ifndef SIGSUSPEND
#include <stdio.h>
#include <signal.h>
void checkset();
void main()
{
// 定义
sigset_t blockset;
// 初始化
sigemptyset(&blockset);
// 加入信号集
sigaddset(&blockset,SIGINT);
sigaddset(&blockset,SIGTSTP);
checkset();
/*
当这样调用函数sigprocmask(0,NULL,&oldset);时,当前的信号掩码会复制一份到oldset。
1)SIG_BLOCK:把set中的信号加到当前信号掩码中。
2)SIG_UNBLOCK:把set中的信号从当前信号掩码中除掉。
3)SIG_SETMASK:把set的信号付给信号掩码。
**/
sigprocmask(SIG_SETMASK,&blockset,NULL);
checkset();
/* blockset所有加到信号掩码中 */
sigaddset(&blockset,SIGTERM);
sigprocmask(SIG_BLOCK,&blockset,NULL);
checkset();
sigdelset(&blockset,SIGTERM);
/* blockset所有从信号掩码中减去 */
sigprocmask(SIG_UNBLOCK,&blockset,NULL);
checkset();
}
void checkset()
{
sigset_t set;
printf("checkset start:\n");
/*
当这样调用函数sigprocmask(0,NULL,&oldset);时,当前的信号掩码会复制一份到oldset。
**/
if(sigprocmask(0,NULL,&set)<0)
{
printf("checksetsigprocmask error!!\n");
exit(0);
}
if(sigismember(&set,SIGINT))
printf("sigint\n");
if(sigismember(&set,SIGTSTP))
printf("sigtstp\n");
if(sigismember(&set,SIGTERM))
printf("sigterm\n");
printf("checkset end\n");
}
#else
#include <stdio.h>
#include <signal.h>
void checkset();
void func();
void main()
{
sigset_t blockset,oldblockset,zeroset,pendmask;
printf("pid:%ld\n",(long)getpid());
signal(SIGINT,func);
sigemptyset(&blockset);
sigemptyset(&zeroset);
sigaddset(&blockset,SIGINT);
sigprocmask(SIG_SETMASK,&blockset,&oldblockset);
checkset();
// 获取被阻塞的信号 到pendmask中
sigpending(&pendmask);
if(sigismember(&pendmask,SIGINT))
printf("SIGINT pending\n");
/*
sigsuspend 用实参 sigmask 指定的信号集代替调用进程的信号屏蔽,
然后挂起该进程直到某个不属于 sigmask 成员的信号到达为止。
此信号的动作要么是执行信号句柄,要么是终止该进程。
如果信号终止进程,则 suspend 函数不返回。
如果信号的动作是执行信号句柄,则在信号句柄返回后,sigsuspend 函数返回,并使
进程的信号屏蔽恢复到 sigsuspend 调用之前的值。
**/
if(sigsuspend(&zeroset)!= -1)
{
printf("sigsuspenderror\n");
exit(0);
}
printf("afterreturn\n");
sigprocmask(SIG_SETMASK,&oldblockset,NULL);
printf("SIGINTunblocked\n");
}
void checkset()
{
sigset_t set;
printf("checksetstart:\n");
if(sigprocmask(0,NULL,&set)<0)
{
printf("checksetsigprocmask error!!\n");
exit(0);
}
if(sigismember(&set,SIGINT))
printf("sigint\n");
if(sigismember(&set,SIGTSTP))
printf("sigtstp\n");
if(sigismember(&set,SIGTERM))
printf("sigterm\n");
printf("checksetend\n");
}
void func()
{
printf("hellofunc\n");
}
#endif