Linux内核编程 信号的屏蔽、冲突

目录

一:信号中断进程

二:信号集操作函数

三:sigprocmask启用屏蔽

四:信号屏蔽

五:信号冲突

六:解决信号冲突问题


一:信号中断进程

进程对于接收到不认识的信号 会直接退出程序,示例如下

#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技术之信号 想要深入学习,下面文章可供参考

信号基础

signal sigaction使用

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Linux内核编程是一种针对Linux操作系统内核进行开发的技术。它不仅仅涉及到Linux内核的理论知识,还需要具备相应的编程技术以及对计算机系统的深入了解。 Linux内核编程的主要目的是为Linux操作系统添加新的特性或修复现有特性的bug。为了实现这些目标,需要掌握C语言等编程语言,并且了解Linux操作系统的内部工作原理。 Linux内核编程主要包括以下内容: 1. 内核模块编程内核模块是一种可以动态加载到Linux内核中的软件,它可以添加新的功能或修改现有功能。通过编写内核模块可以实现对设备驱动程序的开发、文件系统的修改等。 2. 设备驱动程序开发:设备驱动程序是将硬件设备和操作系统连接起来的软件。Linux内核提供了一系列的接口函数和数据结构,用于开发设备驱动程序。掌握设备驱动程序开发技术可以实现对设备的管理和控制。 3. 文件系统的修改:Linux内核支持多种文件系统,但有时候需要根据特定的需求对文件系统进行修改。文件系统的修改需要深入了解文件系统的工作原理和相关的数据结构。 4. 虚拟文件系统(VFS):VFS是Linux内核中用于管理文件的核心模块之一。掌握VFS的开发技术可以实现对文件系统的自定义扩展。 总之,Linux内核编程是一项复杂而有挑战性的技术,需要具备扎实的编程基础和对操作系统原理的深入理解。掌握这项技术可以为Linux操作系统添加新的功能或改进现有功能,提高系统的性能和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chenruhan_QAQ_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值