学习分享
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-31不可靠信号:连续发送不会连续触发处理函数调用,但是间隔发送就会挨个处理,带有操作系统分配的特殊含义
- 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;
}