【Linux基础(三)】信号

本文详细介绍了信号在UNIX系统中的概念、常见信号类型、kill和signal库函数、sigaction和sigqueue的使用,以及处理不可靠和可靠信号的区别,同时探讨了信号冲突及其解决方案。
摘要由CSDN通过智能技术生成

1、信号的基本概念

信号是UNIX系统响应某些状况而产生的事件,进程在接收到信号时会采取相应的行动。
信号是因为某些错误条件而产生的,比如内存段冲突、浮点处理器错误或者非法指令等
它们由shell和终端管理器产生以引起中断。
进程可以生成信号、捕捉并响应信号或屏蔽信号

2、查看信号列表

使用命令:kill -l 查看信号列表

CTRL+C 就是向进程发送2号信号

在这里插入图片描述

  • 1-31为系统信号
  • 34-64为扩展信号,提供开发人员使用

3、常见信号名称

信号的名称是在头文件 signal.h里定义的

在这里插入图片描述
在这里插入图片描述

  • SIGUSR1 和SIGUSR2没有任何含义,由开发人员自由定义

4、signal库函数

类型QT中的connect
在这里插入图片描述

5、发送信号kill

类似QT中的emit
在这里插入图片描述

6、kill - signal (无参信号)示例

在这里插入图片描述

#include <iostream>
#include <unistd.h>
#include <signal.h>
using namespace std;

void signal_function(int num)/信号处理函数
{
	cout<<"pid = "<<getpid()<<"信号处理函数被触发"<<endl;
}
int main()
{
	//信号的注册绑定
	signal(SIGUSR1,signal_funcion);
	pid_t pid =fork();
	
	if(pid>0)
	{
		//父进程
		sleep(5);
		//发送信号
		kill(pid,SIGUSR1);
		while(1)
		{
		}
	}
	else 
	{
		//子进程
		while(1)
		{
			cout<<"子进程pid = "<<getpid()<<endl;
			sleep(1);
		}
	}
	return 0;
}

6.1、kill - signal (不可靠信号)示例

1-31为不可靠信号,连续发送多次,响应1次。不会连续触发处理函数调用,但是间隔发送就会挨个处理。带有操作系统分配的特殊含义

#include <iostream>
#include <unistd.h>
#include <signal.h>
using namespace std;

void signal_function(int num)/信号处理函数
{
	cout<<"pid = "<<getpid()<<"信号处理函数被触发"<<endl;
}
int main()
{
	//信号的注册绑定
	signal(SIGUSR1,signal_funcion);
	pid_t pid =fork();
	
	if(pid>0)
	{
		//父进程
		sleep(5);
		for(int i=0;i<3;i++)
		{
			cout<<"i = "<<i<<endl; 
			//发送信号
			kill(pid,SIGUSR1);
			sleep(1);
		}
		while(1)
		{
		}
	}
	else 
	{
		//子进程
		while(1)
		{
			cout<<"子进程pid = "<<getpid()<<endl;
			sleep(1);
		}
	}
	return 0;
}

6.2、kill - signal (可靠信号)示例

34-64为可靠信号,连续发送会连续触发处理函数调用

#include <iostream>
#include <unistd.h>
#include <signal.h>
using namespace std;

void signal_function(int num)/信号处理函数
{
	cout<<"pid = "<<getpid()<<"信号处理函数被触发"<<endl;
}
int main()
{
	//信号的注册绑定
	signal(SIGUSR1,signal_funcion);
	pid_t pid =fork();
	
	if(pid>0)
	{
		//父进程
		sleep(5);
		for(int i=0;i<3;i++)
		{
			cout<<"i = "<<i<<endl; 
			//发送信号
			kill(pid,SIGRTMIN);
		}
		while(1)
		{
		}
	}
	else 
	{
		//子进程
		while(1)
		{
			cout<<"子进程pid = "<<getpid()<<endl;
			sleep(1);
		}
	}
	return 0;
}

7、信号分类

7.1、信号运行原理分类

  1. 1-31不可靠信号:连续发送不会连续触发处理函数调用,但是间隔发送就会挨个处理,带有操作系统分配的特殊含义
  2. 34-64可靠信号:连续发送会连续触发处理函数调用

7.2、信号是否携带数据分类

1、无参信号:signal - kill
2、携带参数信号 :sigaction - sigqueue

8、sigaction库函数

Linux中查看函数详情命令:man sigaction

在这里插入图片描述

9、sigqueue库函数

Linux中查看函数详情命令:man sigqueue

在这里插入图片描述

10、sigaction - sigqueue(带参信号)示例

#include <iostream>
#include <unistd.h>
#include <signal.h>
using namespace std;

void sigaction_fuction(int num,siginfo_t* info, void*vo)	//num指信号编号
{
	int  res= info->si_int;
	cout<<"pid = "<<getpid()<<"信号处理函数被触发 res="<<res<<endl;
}
int main()
{
	struct sigaction act;
	act.sa_sigaction =sigaction_function://带参信号处理函数
	act.sa_flags = SA_SIGINFO;//当前信号带参数
	
	sigction(SIGUSR1,&act,NULL);//带参信号的绑定

	pid_t pid =fork();
	
	if(pid>0)
	{
		//父进程
		sleep(5);
		
		//带参信号发送
		union sigval val;//联合体
		val.sival_int =1001;
		sigqueue(pid,SIGUSR1,val);
		while(1)
		{
		}
	}
	else 
	{
		//子进程
		while(1)
		{
			cout<<"子进程pid = "<<getpid()<<endl;
			sleep(1);
		}
	}
	return 0;
}

11、屏蔽信号

11.1、信号集操作函数

在这里插入图片描述

11.2、sigprocmask函数

在这里插入图片描述
在这里插入图片描述

11.3、屏蔽信号示例

#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
using namespace std;
void sigaction_fuction(int num,siginfo_t* info, void*vo)	//num指信号编号
{
	int  res= info->si_int;
	cout<<"pid = "<<getpid()<<"信号处理函数被触发 res="<<res<<endl;
}
int main()
{
	struct sigaction act;
	act.sa_sigaction =sigaction_function://带参信号处理函数
	act.sa_flags = SA_SIGINFO;//当前信号带参数
	sigction(SIGUSR1,&act,NULL);//带参信号的绑定

	pid_t pid =fork();
	
	if(pid>0)
	{
		//父进程
		sleep(5);
		
		//带参信号发送
		union sigval val;//联合体
		val.sival_int =1001;
		sigqueue(pid,SIGUSR1,val);
		while(1)
		{
		}
	}
	else 
	{
		//子进程

		//屏蔽信号
		//创建信号集
		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;
}

12、信号冲突

当一个进程接收到一个信号,去执行该信号的处理函数,但是信号处理函数还没执行完,就收到另一个信号。

12.1、信号冲突示例


#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
using namespace std;
void test1(int num)	
{
	cout<<"test1开始运行"<<endl;
	sleep(30);
	cout<<"test1结束运行"<<endl;
}
void test2(int num)
{
	cout<<"test2 运行 ....."<<endll;
}
int main()
{
	struct sigaction act1;
	act.sa_sigaction =test1:
	act1.flags = 0;//无参信号
	
	
	struct sigaction act2;
	act.sa_sigaction =test2;
	act2.flags =0;//无参信号
	
	sigction(SIGUSR1,&act1,NULL);
	sigction(SIGUSR2,&act2,NULL);
	
	while(1)
	{
		cout<<"进程pid = "<<getpid()<<endl;
		sleep(1);
	}
	
	return 0;
}

在这里插入图片描述

12.2、信号冲突解决方案示例


#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
using namespace std;
void test1(int num)	
{
	cout<<"test1开始运行"<<endl;
	sleep(30);
	cout<<"test1结束运行"<<endl;
}
void test2(int num)
{
	cout<<"test2 运行 ....."<<endll;
}
int main()
{
	struct sigaction act1;
	act.sa_sigaction =test1:
	act1.flags = 0;//无参信号
	
	
	struct sigaction act2;
	act.sa_sigaction =test2;
	act2.flags =0;//无参信号
	//信号1在处理时不希望信号2来打扰
	//所以在信号1的struct  sigaction结构体中拉黑了信号2
	
	sigemptyset(&(act1.sa_mask));//将act1.sa_mask设置为空信号集。
	//将SIGUSR2信号添加到act1.sa_mask中。sa_mask成员用于指定在执行信号处理函数时需要阻塞的信号集合。
	sigaddset(&(act1.sa_mask),SIGUSR2);
	sigction(SIGUSR1,&act1,NULL);
	sigction(SIGUSR2,&act2,NULL);
	
	while(1)
	{
		cout<<"进程pid = "<<getpid()<<endl;
		sleep(1);
	}
	
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值