linux系统编程之信号(signal)的使用方法案例
信号处理过程:
中断源-》中断屏蔽-》保护现场-》中断处理程序-》中断恢复
信号称为软中断
//kill -l 查看所有signal信号 共计64个信号
//man 7 signal 查看signal信号的意思
//信号提供了一种异步处理的一种能力;
//action 是默认操作 在man 7 signal里面的表里面
//ctrl + \ 可以杀死3) SIGQUIT 退出程序
//signal(SIGINT,SIG_DFL) //从新关联了默认程序
一)信号与中断
(1)信号与中断的相似点
1)都采用异步通讯
2)都可以处理相应的信号(中断)服务程序
3)都可以返回
4)对信号或中断信号都可以进行屏蔽
(2)信号与中断的区别
1)中断有优先级,信号没有优先级
2)信号是用户态运行,中断是内核态运行
3)中断相应是及时的,信号是有延时的!
(3)信号的三种相应
1)忽略信号
2)捕获并处理信号
3)执行默认操作
二)signal信号的注册及简单应用
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
using namespace std;
#define ERR_EXIT(m) \do \{\perror(m);\exit(EXIT_FAILURE);\}while(0)
void handler(int num)
{cout<<"输出 num:"<<num<<endl;
}
int main(void)
{ // signal(SIGINT,handler); //安装(注册)一个信号,就是说将一个SIGINT信号和handler函数关联起来if(signal(SIGINT,handler) == SIG_ERR) //也可以对返回值进行处理{ERR_EXIT("signal error");}while(1);return 0;
}
小插曲:
/ /queue::iterator it1; //单端队列不可以遍历,没有迭代器
deque::iterator it2; //双端队列可以遍历
string::iterator i3; //string肯定可以遍历
二)信号分为可靠信号和不可靠信号
SIGRT runtime 实时信号也叫可靠信号 从34到64之后
1) signal 向父进程发送一个信号
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>using namespace std;#define ERR_EXIT(m) \do \{\perror(m);\exit(EXIT_FAILURE);\}while(0)void handler(int num)
{cout<<"输出 num:"<<num<<endl;
}int main(void)
{ signal(SIGUSR1,handler); //安装(注册)一个信号,就是说将一个SIGINT信号和handler函数关联起来pid_t pid = fork();if(pid == 0){kill(getppid(),SIGUSR1);//向父进程发送一个信号//pid = getpgrp();//kill(-pid,SIGUSR1);//向进程组发送一个信号;exit(EXIT_SUCCESS);}int n = 2;do{n = sleep(n); //剩余时间} while (n > 0);return 0;
}
三)pause函数在signal中的使用
1) pause函数使用方法;
//pause会睡眠,使调用者进程挂起,直到信号被唤醒才可以继续运行
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>using namespace std;void handler(int num)
{cout<<"输出 num:"<<num<<endl;sleep(1);
}int main(void)
{ signal(SIGINT,handler); //安装(注册)一个信号,就是说将一个SIGINT信号和handler函数关联起来while(1){pause(); //pause函数进入中断睡眠状态cout<<"pause return"<<endl;}return 0;
}
四)更多信号学习
alarm SIGALRM //发送一个时钟信号
setitimer SIGALRM SIGVTALRM SIGGPROF
abort SIGABRT
给一个a.out的进程发送一个alrm信号的方法:
kill -ALRM ps aux|grep a.out|grep -v vi|grep -v grep|awk '{print $2}'
alarm函数的使用方法:
//alarm函数使用方法
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>using namespace std;void handler(int num)
{cout<<"输出 num:"<<num<<endl;sleep(1);
}int main(void)
{ signal(SIGALRM,handler); //安装(注册)一个信号,就是说将一个SIGINT信号和handler函数关联起来alarm(1);while(1){pause(); //pause会睡眠,使调用者进程挂起,直到信号被唤醒才可以继续运行alarm(1); //每个1妙发送一个信号}return 0;
}
//在信号处理函数中,应使用可重入函数!!!
//信号从产生到递达的过程;
man sigpending 获取当前信号的未决状态集!
//信号集操作函数如下:
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
int sigismember(const sigset_t *set, int signum);
信号产生的过程:
信号从产生状态到递达状态,中间经过了一个未决状态;
未决状态产生的条件是信号发生的时候,信号被阻塞,如果阻塞被解除,则信号会变成递达状态;
五)sigprocmask sigemptyset sigaddset sigpending等函数的综合应用
测试代码如下:
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>using namespace std;void handler(int sig)
{if(sig == SIGINT)cout<<"recv sig:"<<sig<<endl;else if(sig == SIGQUIT){sigset_t uset;sigemptyset(&uset);sigaddset(&uset,SIGINT);sigprocmask(SIG_UNBLOCK,&uset,NULL); //去除屏蔽,}
}void sigprint(sigset_t* set)
{int i;for(i = 1; i<NSIG; i++){if(sigismember(set,i))putchar('1');else {putchar('0');}}printf("\n"); //没有这句话,上面的不会正确输出,因为数据都在缓存里面呢!
}
int main(void)
{ signal(SIGINT,handler); //安装(注册)一个信号,就是说将一个SIGINT信号和handler函数关联起来signal(SIGQUIT,handler);sigset_t pset; //p pending 的意思sigset_t bset; //b应该是block 阻塞的意思sigemptyset(&bset);sigaddset(&bset,SIGINT); //把SIGINT信号加入到集合中sigprocmask(SIG_BLOCK,&bset,NULL); //把SIGINT信号使能阻塞,模拟信号触发后,会屏蔽,这样就不会递达while(1){sigpending(&pset);sigprint(&pset);sleep(1);}return 0;
}
上述代码功能测试操作:
ctrl+c,差生sigint 信号,此时会产生屏蔽,“1”,ctrl+,会去除屏蔽,
killall a.out //杀死a.out进程
六)sigaction信号安装函数的使用方法
//信号被屏蔽了,就是被阻塞了
//按ctrl+c,则会输出结果
//sigaction即是结构体,又是函数名!
用sigaction安装sigint信号的案例
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>using namespace std;void handler(int sig)
{cout<<"recv sig:"<<sig<<endl;
}int main(void)
{ struct sigaction act;act.sa_handler = handler; //函数指针sigemptyset(&act.sa_mask);act.sa_flags = 0;sigaction(SIGINT,&act,NULL); //注册SIGINT信号函数while(1){pause();}return 0;
}
七)sigaction的sa_mask的使用方法:
注:sa_mask如何影响sigaction函数的行为!
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>using namespace std;void handler(int sig)
{cout<<"recv sig:"<<sig<<endl;sleep(5);
}int main(void)
{ struct sigaction act;act.sa_handler = handler;sigemptyset(&act.sa_mask);sigaddset(&act.sa_mask,SIGQUIT); //将SIGQUIT加入到掩码当中,(SIGQUIT被屏蔽了)act.sa_flags = 0;sigaction(SIGINT,&act,NULL); //注册SIGINT信号函数while(1){pause();}return 0;
}
测试结果:
./a.out
^Crecv sig:2
^^^^^^^^^^\退出 (核心已转储) //不能马上退出,因为SIGQUIT信号被屏蔽了
jiang@jiang-ThinkPad-X280:~/Cpp-Concurr
七)sigqueue函数的应用
sigqueue主要应用进程间通信!
//发送进程:
向一个进程发送SIGINT信号,并且将整型100也传进去!
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>int main(int argc,char *argv[])
{if(argc!=2){printf("arguments error!");exit(0);}pid_t pid=atoi(argv[1]);//将进程号转化为整数union sigval v;v.sival_int=100; //初始化sival_int的值sigqueue(pid,SIGINT,v);//向pid发送SIGINT信号,并且传递额外信息vreturn 0;
}
接收进程:
此进程等待接受信号的传入,并有SIGINT的信号处理函数!
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<string.h>
#include<stdlib.h>void handler(int,siginfo_t *,void *);int main(void)
{struct sigaction act;act.sa_sigaction=handler;sigemptyset(&act.sa_mask);act.sa_flags=SA_SIGINFO; //必须填写SA_SIGINFO才可以进行进程间通信,传递数据if(sigaction(SIGINT,&act,NULL)<0){printf("error");exit(0);}for(;;)pause();return 0;
}void handler(int sig,siginfo_t * info,void *ctx)
{printf("recv a sid=%d data=%d data=%d\n",sig,info->si_value.sival_int,info->si_int);//打印接收信息
}
测试结果如下:
终端执行命令: ./a.out 10728
打开另一终端:./recv
收到的数据是:recv a sid=2 data=100 data=100
八)信号的可靠性和不可靠性
发送进程:
发送三个可靠信号和三个不可靠信号,延时3妙后,发送恢复屏蔽信号,代码如下:
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>int main(int argc,char *argv[])
{if(argc!=2){printf("arguments error!");exit(0);}pid_t pid=atoi(argv[1]);//将进程号转化为整数union sigval v;v.sival_int=100; //初始化sival_int的值sigqueue(pid,SIGINT,v);//向pid发送SIGINT信号,并且传递额外信息vsigqueue(pid,SIGINT,v);//向pid发送SIGINT信号,并且传递额外信息vsigqueue(pid,SIGINT,v);//向pid发送SIGINT信号,并且传递额外信息vsigqueue(pid,SIGRTMIN,v);//向pid发送SIGINT信号,并且传递额外信息vsigqueue(pid,SIGRTMIN,v);//向pid发送SIGINT信号,并且传递额外信息vsigqueue(pid,SIGRTMIN,v);//向pid发送SIGINT信号,并且传递额外信息v sleep(3);kill(pid,SIGUSR1);return 0;
}
接收进程:
设置一个可靠信号(信号排队),一个不靠信号,和一个屏蔽字恢复信号,使之解除阻塞,代码如下:
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<string.h>
#include<stdlib.h>void handler(int);int main(void)
{struct sigaction act;act.sa_handler=handler;sigemptyset(&act.sa_mask);act.sa_flags=0;sigset_t s;sigemptyset(&s);sigaddset(&s,SIGINT);sigaddset(&s,SIGRTMIN);sigprocmask(SIG_BLOCK,&s,NULL); //SIGINT或者SIGRTMIN信号到来的时候,就会被阻塞sigaction(SIGINT,&act,NULL); //不可靠信号sigaction(SIGRTMIN,&act,NULL);//可靠信号sigaction(SIGUSR1,&act,NULL);//安装一个信号,解除阻塞for(;;)pause();return 0;
}void handler(int sig)
{if(sig == SIGINT || sig == SIGRTMIN){printf("recv a sid=%d\n",sig);//打印接收信息}else if(sig == SIGUSR1){sigset_t s;sigemptyset(&s);sigaddset(&s,SIGINT);sigaddset(&s,SIGRTMIN);sigprocmask(SIG_UNBLOCK,&s,NULL);}
}
测试结果如下:
接收进程运行结果:
./recv
recv a sid=34
recv a sid=34
recv a sid=34
recv a sid=2
发送进程运行结果:
./send 4739 //4739为接收进程号
linux系统编程之信号(signal)的使用方法案例相关推荐
- linux系统发送信号的系统调用是,linux系统编程之信号:信号发送函数sigqueue和信号安装函数sigaction...
信号发送函数sigqueue和信号安装函数sigaction sigaction函数用于改变进程接收到特定信号后的行为. sigqueue()是比较新的发送信号系统调用,主要是针对实时信号提出的(当然 ...
- 【Linux系统编程】信号 (下)
00. 目录 文章目录 00. 目录 01. 信号集 02. 信号阻塞集 03. sigaction函数 04. 附录 01. 信号集 为了方便对多个信号进行处理,一个用户进程常常需要对多个信号做出处 ...
- 【Linux系统编程】信号 (上)
00. 目录 文章目录 00. 目录 01. 信号概述 02. 信号编号 03. 信号产生方式 04. kill发送信号 05. pause等待信号 06. 信号处理方式 07. 信号处理函数 08. ...
- linux系统编程之信号(一):信号基本概述
一.为了理解信号,先从我们最熟悉的场景说起: 1. 用户输入命令,在Shell下启动一个前台进程. 2. 用户按下Ctrl-C,这个键盘输入产生一个硬件中断. 3. 如果CPU当前正在执行这个进程的代 ...
- linux系统编程之信号(四):信号的捕捉与sigaction函数
一.内核如何实现信号的捕捉 如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号.由于信号处理函数的代码是在用户空间的,处理过程比较复杂,举例如下: 1. 用户程序注册了SI ...
- Linux系统编程(二)–信号
文章目录 1 Hello signal 1.1 hello signal 程序 1.2 向 hello signal 发信号 1.3 招待你的"客人" 1.3.1 signal 函 ...
- Linux系统编程47 信号 - setitimer(),优先使用setitimer()计时
NAMEgetitimer, setitimer - get or set value of an interval timerSYNOPSIS#include <sys/time.h>i ...
- linux系统编程之信号(五)
今天继续对信号进行学习,开始正入正题: sigaction函数: 安装信号之前我们已经学过一个函数:signal,它最早是在unix上出现的,它是对不可靠信号进行安装的,之后出现了可靠信号和实时信号, ...
- linux系统编程下的open函数使用方法
目录 1.句柄(file descriptor 简称fd) 2.使用open前需要先包含头文件 3.参数说明 3.1 参数1(pathname) 3.2 参数2(flags) 3.3 参数3(mode ...
最新文章
- 使用let替换var实现块级作用域的小发现
- 5G — 3 大场景、8 大 KPI
- 每日一皮:只有第一名才能拿金牌...
- JDK12下的ArrayList源码解读 与 Vector的对比
- java程序不能编译_救命-JAVA程序不能编译!
- 【Oracle】多表连接查询详解
- python列表函数方法_与Python列表相关的函数
- js (jQuery)分组数据
- mysql 存储过程使用参数_mysql 存储过程 使用参数
- ubuntu和windows双系统启动顺序的修改
- win10字体显示Mac效果+Chrome字体效果增强
- iOS语音转文字实现
- Java项目:调查问卷管理系统(java+SpringBoot+Vue+ElementUI+Maven+mysql)
- Qt使用OpenCv
- VSCode悬停提示
- 怎么升级计算机配置,旧电脑配置升级攻略,看完再决定要不要配置新电脑
- 全球台式计算机出货量,Gartner:2020年全球PC电脑出货量达到2.75亿台 同比增长4.8%...
- 字节流和字符流的应用
- 帆软参数为空查询全部
- cocos2dx lua 热更新