上篇文章中,我给大家介绍了关于信号产生的几种方式。本期,我将给大家介绍的是关于 “信号的保存” 的相关知识!!!
目录
(一)信号常见概念的概念
(二)在内核中的表示
2.1 原理表示
2.2 代码演示
2.3 sigset_t
(三)信号集操作函数
3.1 sigprocmask
3.2 sigpending
首先,在正式的介绍本期内容之前,先给大家科普一下信号其他相关常见概念,便于后续的表述理解!!
注意:阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。
信号在内核中的表示示意图:
【解释说明】
因此,正基于上述表结构,我们之前才说进程是能够识别一个信号的:
【解释说明】
接下来,我简单演示此处的捕捉行为。
int main()
{
//#define SIG_DFL ((__sighandler_t) 0) /* Default action. */
//typedef void (*__sighandler_t) (int);
signal(2, SIG_DFL); //处理为默认动作
while(true)
{
sleep(1);
}
return 0;
}
【解释说明】
效果展示:
int main()
{
// #define SIG_IGN ((__sighandler_t) 1) /* Ignore signal. */
// typedef void (*__sighandler_t) (int);
signal(2,SIG_IGN);
while(true)
{
sleep(1);
}
return 0;
}
效果展示:
sigset_t类型对于每种信号用一个bit表示“有效”或“无效”状态,至于这个类型内部如何存储这些bit则依赖于系统实现,从使用者的角度是不必关心的,使用者只能调用以下函数来操作sigset_ t变量,而不应该对它的内部数据做任何解释,比如用printf直接打印sigset_t变量是没有意义的
#include
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset (sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set, int signo);
【解释说明】
调用函数sigprocmask可以读取或更改进程的信号屏蔽字(阻塞信号集)
#include
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
返回值:若成功则为0,若出错则为-1
【解释说明】
假设当前的信号屏蔽字为mask,下表说明了how参数的可选值:
假设今天我想对 2号信号进行屏蔽操作。代码如下:
void showBlock(sigset_t *oset){
int signo = 1;
for(; signo <=31; signo++)
{
if(sigismember(oset, signo)) cout << "1";
else cout << "0";
}
cout << endl;
}
int main()
{
sigset_t oset,set;
sigemptyset(&set);
sigemptyset(&oset);
sigaddset(&set,2);
sigprocmask(SIG_SETMASK,&set,&oset);
int cnt = 0;
while(true)
{
showBlock(&oset);
sleep(1);
cnt++;
if(cnt == 10)
{
cout << "recover block" << endl;
sigprocmask(SIG_SETMASK, &oset, &set);
showBlock(&set);
}
}
return 0;
}
效果展示:
#include
sigpending
读取当前进程的未决信号集,通过set参数传出。调用成功则返回0,出错则返回-1。
void showBlock(sigset_t *oset){
int signo = 1;
for(; signo <=31; signo++)
{
if(sigismember(oset, signo)) cout << "1";
else cout << "0";
}
cout << endl;
}
static void handler(int signo){
cout << "对特定信号:"<< signo << "执行捕捉动作" << endl;
}
static void PrintPending(const sigset_t &pending){
cout << "当前进程的pending位图: ";
for(int signo = 1; signo <= 31; signo++)
{
if(sigismember(&pending, signo)) cout << "1";
else cout << "0";
}
cout << "\n";
}
int main()
{
// 2.0 设置对2号信号的的自定义捕捉
signal(2, handler);
int cnt = 0;
//1. 屏蔽2号信号
sigset_t set,oset;
//1.1 初始化
sigemptyset(&set);
sigemptyset(&oset);
// 1.2 将2号信号添加到set中
sigaddset(&set,2);
// 1.3 将新的信号屏蔽字设置进程
sigprocmask(SIG_BLOCK,&set,&oset);
//2. while获取进程的pending信号集合,并01打印
while (true)
{
// 2.1 先获取pending信号集
sigset_t pending;
sigemptyset(&pending);
int n = sigpending(&pending);
assert(n == 0);
(void)n; //保证不会出现编译是的warning
// 2.2 打印
PrintPending(pending);
sleep(1);
//2.4 10s之后,恢复对所有信号的block动作
if(cnt++ == 10)
{
cout << "解除对2号信号的屏蔽" << endl; //先打印
sigprocmask(SIG_SETMASK, &oset, nullptr); //?
}
}
return 0;
}
效果展示:
以上便是本期关于信号的保存的相关内容!!!