目录
一:信号中断进程
进程对于接收到不认识的信号 会直接退出程序,示例如下
#include<iostream>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
using namespace std;
int main()
{
while (1)
{
cout << "进程正在运行 ... pid=" << getpid() << endl;
sleep(1);
}
return 0;
}
kill -10 73864,(10 用户自定义信号)在图中不难看出,发送用户自定义信号,
进程在不认识信号应该怎么处理的情况下,程序就自己退出了
kill -12 74483 ,(12 用户自定义信号),同样出现在发送信号后,程序自己退出的情况
不认识的信号 也就是没有做信号绑定处理函数 称为未决信号
若是kill -9 xxx,程序结束是正常的,因为-9就是结束进程
但对于-10 -12 用户自定义信号,进程在遇到不认识的信号(未决信号),不知道如何处理,进程就会停止(类似于程序异常退出的情况),对于这样的情况,需要学习如何解决
方案:屏蔽信号
sigset_t 信号集
sigemptyset 清空信号集
sigaddset 添加信号到信号集
sigdelset 从信号集删除信号
sigfillset 添加所有信号
sigismember 判断信号是否在信号集中
sigprocmask 启用屏蔽
二:信号集操作函数
多个信号集中(信号集-信号的集合),一次性进行处理(类似对一批信号进行增删改查操作)
#include <signal.h>
/* Clear all signals from SET. */
int sigemptyset(sigset_t *set);// 清空信号集(相当于初始化操作)
/* Set all signals in SET. */
int sigfillset(sigset_t *set);// 所有信号加进去 32 33 是没有的(添加所有)
int sigaddset(sigset_t *set, int signo);// 增加信号(添加单个)
int sigdelset(sigset_t *set, int signo);//删除信号集的某个信号
int sigismember(const sigset_t *set, int signo);// 信号是否在集合里面
/* Return 1 if SIGNO is in SET, 0 if not. */
三:sigprocmask启用屏蔽
sigprocmask 读取或更改进程的信号屏蔽字【屏蔽信号】
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
功能:读取或更改进程的信号屏蔽字。
返回值:若成功则为0,若出错则为-1
如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出
如果set是非空指针,则更改进程的信号屏蔽字,参数how指示如何更改
如果oset和set都是非空指针,则先将原来的信号屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字
假设当前的信号屏蔽字为mask,下表说明了how参数的可选值
若是进程要保证正常的运行,不想要 有其他的信号来干扰当前进程的逻辑运行,只需要使用信号屏蔽
四:信号屏蔽
屏蔽用户自定义信号 示例如下
#include<iostream>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include<stdio.h>
using namespace std;
int main()
{
//屏蔽信号:进程运行期间避免被其他的信号干扰而打断进程的正常运行
//创建信号集
sigset_t array;
//初始化信号集(清空信号集)
sigemptyset(&array);
//添加想要屏蔽的信号
sigaddset(&array, SIGUSR1);
sigaddset(&array, SIGUSR2);
//启用屏蔽
if (sigprocmask(SIG_BLOCK, &array, NULL) < 0)
{
perror("sigprocmask error");
}
while (1)
{
cout << "进程正在运行 ... pid=" << getpid() << endl;
sleep(1);
}
return 0;
}
kill -10 74740 和 kill -12 74740 都没有结束进程,因为已经将用户自定义信号SIGUSR1和SIGUSR2信号屏蔽了
但是 -9 信号编号【SIGKILL】 不可屏蔽,这是系统特定的停止进程信号
五:信号冲突
绑定两个信号 ,只要信号发送就过来,就要处理相应的函数
若是绑定两个不同的函数,一个函数执行快,另外一个函数执行慢,会出现信号冲突的情况
#include<iostream>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include<stdio.h>
using namespace std;
void test1(int num)
{
cout << "test1 run..........." << endl;
sleep(20);//延时处理
cout << "test1 over" << endl;
}
void test2(int num)
{
cout << "test2 run ........" << endl;
}
int main()
{
//信号冲突
//sigaction结构体
struct sigaction act1;
act1.sa_handler = test1;//不带参信号 一个执行快 一个执行慢 模拟信号冲突
act1.sa_flags = 0;
//sigaction结构体
struct sigaction act2;
act2.sa_handler = test2;//不带参信号 一个执行快 一个执行慢 模拟信号冲突
act2.sa_flags = 0;
//绑定信号
sigaction(SIGUSR1, &act1, NULL);
sigaction(SIGUSR2, &act2, NULL);
while (1)
{
cout << "进程正在运行 ... pid=" << getpid() << endl;
sleep(1);
}
return 0;
}
一次kill -10 75133 另一次kill -12 75133 ,发送不同信号
在test1执行期间(还没有执行完),逻辑突然被test2打断,去执行test2,test2执行完后再回去执行test1
这样的业务流程显然不合理
对于这种信号冲突问题,需要解决
若是发送相同信号,如下
kill -10 发送多次
由结果看出,虽然发了多次信号,但是一定会先走完一次,才会去走下一次
综上:信号冲突分为两种情况
情况1:一个信号正在执行处理函数,还在执行没有执行完的时候,接收到异种信号,此时执行函数会被打断立刻执行异种信号处理,异种信号处理完再回去处理未处理完的第一个信号的逻辑。
情况2:一个信号正在执行处理函数,还在执行没有执行完的时候,接收到了同种信号,执行函数继续执行,完成之后再次执行下一次函数
速记:异种打断,同种排队
同种排队属于正常的,但是异种打断这种不正常的就需要进行解决
方案:使用sigaction绑定信号使用sa_mask
若是SIGUSR1不希望被打断,就找SIGUSR1的struct sigaction
六:解决信号冲突问题
结构体中第3个属性
sigset_t 信号集 ,处理sa_mask信号集
如:SIGUSR1不希望被打断,就找SIGUSR1 的 struct sigaction
//SIGUSR1不希望被打断,就找SIGUSR1 的 struct sigaction
sigemptyset(&(act1.sa_mask));
sigaddset(&(act1.sa_mask), SIGUSR2);
#include<iostream>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include<stdio.h>
using namespace std;
void test1(int num)
{
cout << "test1 run..........." << endl;
sleep(20);//延时处理
cout << "test1 over" << endl;
}
void test2(int num)
{
cout << "test2 run ........" << endl;
}
int main()
{
//信号冲突
//sigaction结构体
struct sigaction act1;
act1.sa_handler = test1;//不带参信号 一个执行快 一个执行慢 模拟信号冲突
act1.sa_flags = 0;
//sigaction结构体
struct sigaction act2;
act2.sa_handler = test2;//不带参信号 一个执行快 一个执行慢 模拟信号冲突
act2.sa_flags = 0;
//SIGUSR1不希望被打断,就找SIGUSR1 的 struct sigaction
sigemptyset(&(act1.sa_mask));
sigaddset(&(act1.sa_mask), SIGUSR2);
//绑定信号
sigaction(SIGUSR1, &act1, NULL);
sigaction(SIGUSR2, &act2, NULL);
while (1)
{
cout << "进程正在运行 ... pid=" << getpid() << endl;
sleep(1);
}
return 0;
}
可以看出,异种信号冲突,不会被打断
解决了信号冲突的问题
对于 IPC技术之信号 想要深入学习,下面文章可供参考