标题:[Linux]信号(signal)详解(三):信号总结、信号在实操编码中如何应用
@水墨不写bug
(图片来源于文心一言)
目录
一、信号相关常见库函数的使用
(1)sigset_t类型
(2)signal函数与sigaction函数
二、信号总结
正文开始:
一、信号相关常见库函数的使用
在前两次对信号的讲解中,我们已知信号的重要作用以及意义,信号的本质等。接下来我会列举一些常用的库函数,并讲解它们的作用以及意义。
(1)sigset_t类型
这个类型本质就是一个位图,这个位图的每一bit位表示一个状态(非0即1),由于这个位图是库函数维护的,所以不允许用户直接修改这个位图的内容,想要修改,需要用到对应的库函数。
头文件:<signal.h>
//表示初始化set所指向的信号集,使其中所有信号的对应bit清零,表示这个信号集不包含任何有效信号 int sigemptyset(sigset_t *set);//初始化set所指向的信号集,使其中所有信号的对应bit置1,表示 该信号集的有效信号包括系统支持的所有信号 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);
注意:
i,在使用sigset_ t类型的变量之前,一定要调用sigemptyset或sigfillset做初始化,使信号集处于确定的状态。
ii,初始化sigset_t变量之后就可以在调用sigaddset和sigdelset在该信号集中添加或删除某种有效信号。
iii,sigismember是一个布尔函数,用于判断一个信号集的有效信号中是否包含某种 信号,若包含则返回1,不包含则返回0,出错返回-1。
(2)signal函数与sigaction函数
signal()函数原型:
参数:
signum:用户规定的信号标号;
handler:函数指针,返回值void ,参数为int;
作用:
sigaction函数原型:
参数:
signum:用户规定的信号标号;
第二个、第三个参数是结构体类型,这个结构体类型包含有与信号相关的各种信息,定义这个结构体的意义就是为了方便维护信号管理。
结构体原型:
act:结构体类型,使用之前需要设置各种参数,具体参数设置见实例;
oldact:与act相同的结构体类型,传递这个参数的意义就是保存设置act之前的参数设置,如果想要恢复oldact,可以直接使用oldact。
作用:
捕捉用户规定的signum信号,并在捕捉到对应的信号的时候,跳转执行结构体内部的handler函数。(这里的handler函数被设置在结构体内部)
综合两个函数的应用实例:
#include <signal.h>
#include <unistd.h>
#include <iostream>using std::cout;
using std::endl;
bool loop = true;void Print(sigset_t &pending)
{for (int sig = 31; sig > 0; sig--) // 没有0号信号,信号的范围1——31,两闭{if (sigismember(&pending, sig)){cout << 1;}else{cout << 0;}}cout << endl;
}
/*一旦检测到3号信号,会走这里的处理逻辑,此时吧loop置false,使得对2号信号的处理逻辑结束。*/
void donesig2(int sig)
{cout << "get sig 3" << endl;cout << "loop = false, done sig2" << endl;loop = false;
}
void sigcb(int sig)
{loop = true;cout << "get a sig:" << sig << endl;while (loop){sigset_t pending;sigpending(&pending);//函数接口:获取目前的pending位图Print(pending);//打印出pending位图,便于观察sleep(1);signal(3, donesig2);//检测3号信号——在处理信号的同时依然可以接受并处理信号}
}int main()
{struct sigaction ac, oac;//一个结构体类型,内部存储有维护信号系统的一系列变量ac.sa_flags = 0;//暂时设为0/*sa_mask是一个sigset_t类型的位图(sigset_t是一个专门用于维护31个信号位的类型)此处这个函数的作用是把这个位图的所有位置全置0(初始化)但是这个位图目前还没有被设置进操作系统的信号位图*/sigemptyset(&ac.sa_mask);/*sa_handler是结构体内部的一个成员,是一个函数指针类型,需要用户自定义实现,也就是当进程接受到特定信号之后需要做的处理动作*/ac.sa_handler = sigcb;while (true){//这是一个和上述的结构体类型同名称的一个函数//参数:(需要屏蔽的信号,需要设置结构体类型,老的结构体类型,目的是为了保存设置之前的数据,防止用户想要撤回操作)sigaction(2, &ac, &oac);//对2号信号进行特殊处理sleep(1);cout << "I am process:" << getpid() << endl;}return 0;
}
二、信号总结
综合关于操作系统的三篇文章,关于信号的讨论,无非围绕一个时间轴:
信号的产生:本质是由OS产生与发送,本质就是OS向pending位图中写入数据,改变bit位的状态。
信号的保存,需要注意的就是三张位图的理解:
block位图:是否需要屏蔽信号;
pending位图:是否收到信号;
handler位图:如何处理信号;
信号的处理,包括默认(SIG_DFL),忽略(SIG_IGN),用户自定义处理(用户定义的函数指针)。
除此之外,需要熟悉进程的两态转变。
完~