信号处理过程:
中断源-》中断屏蔽-》保护现场-》中断处理程序-》中断恢复
信号称为软中断
//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)的使用方法案例相关推荐

  1. linux系统发送信号的系统调用是,linux系统编程之信号:信号发送函数sigqueue和信号安装函数sigaction...

    信号发送函数sigqueue和信号安装函数sigaction sigaction函数用于改变进程接收到特定信号后的行为. sigqueue()是比较新的发送信号系统调用,主要是针对实时信号提出的(当然 ...

  2. 【Linux系统编程】信号 (下)

    00. 目录 文章目录 00. 目录 01. 信号集 02. 信号阻塞集 03. sigaction函数 04. 附录 01. 信号集 为了方便对多个信号进行处理,一个用户进程常常需要对多个信号做出处 ...

  3. 【Linux系统编程】信号 (上)

    00. 目录 文章目录 00. 目录 01. 信号概述 02. 信号编号 03. 信号产生方式 04. kill发送信号 05. pause等待信号 06. 信号处理方式 07. 信号处理函数 08. ...

  4. linux系统编程之信号(一):信号基本概述

    一.为了理解信号,先从我们最熟悉的场景说起: 1. 用户输入命令,在Shell下启动一个前台进程. 2. 用户按下Ctrl-C,这个键盘输入产生一个硬件中断. 3. 如果CPU当前正在执行这个进程的代 ...

  5. linux系统编程之信号(四):信号的捕捉与sigaction函数

    一.内核如何实现信号的捕捉 如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号.由于信号处理函数的代码是在用户空间的,处理过程比较复杂,举例如下: 1. 用户程序注册了SI ...

  6. Linux系统编程(二)–信号

    文章目录 1 Hello signal 1.1 hello signal 程序 1.2 向 hello signal 发信号 1.3 招待你的"客人" 1.3.1 signal 函 ...

  7. Linux系统编程47 信号 - setitimer(),优先使用setitimer()计时

    NAMEgetitimer, setitimer - get or set value of an interval timerSYNOPSIS#include <sys/time.h>i ...

  8. linux系统编程之信号(五)

    今天继续对信号进行学习,开始正入正题: sigaction函数: 安装信号之前我们已经学过一个函数:signal,它最早是在unix上出现的,它是对不可靠信号进行安装的,之后出现了可靠信号和实时信号, ...

  9. linux系统编程下的open函数使用方法

    目录 1.句柄(file descriptor 简称fd) 2.使用open前需要先包含头文件 3.参数说明 3.1 参数1(pathname) 3.2 参数2(flags) 3.3 参数3(mode ...

最新文章

  1. 使用let替换var实现块级作用域的小发现
  2. 5G — 3 大场景、8 大 KPI
  3. 每日一皮:只有第一名才能拿金牌...
  4. JDK12下的ArrayList源码解读 与 Vector的对比
  5. java程序不能编译_救命-JAVA程序不能编译!
  6. 【Oracle】多表连接查询详解
  7. python列表函数方法_与Python列表相关的函数
  8. js (jQuery)分组数据
  9. mysql 存储过程使用参数_mysql 存储过程 使用参数
  10. ubuntu和windows双系统启动顺序的修改
  11. win10字体显示Mac效果+Chrome字体效果增强
  12. iOS语音转文字实现
  13. Java项目:调查问卷管理系统(java+SpringBoot+Vue+ElementUI+Maven+mysql)
  14. Qt使用OpenCv
  15. VSCode悬停提示
  16. 怎么升级计算机配置,旧电脑配置升级攻略,看完再决定要不要配置新电脑
  17. 全球台式计算机出货量,Gartner:2020年全球PC电脑出货量达到2.75亿台 同比增长4.8%...
  18. 字节流和字符流的应用
  19. 帆软参数为空查询全部
  20. cocos2dx lua 热更新

热门文章

  1. python for循环从第二个元素开始遍历
  2. 【ClickHouse系列】clickhouse-copier是如何进行数据迁移的
  3. Linux内核模块编写详解
  4. MySQL,刷题之对视图操作,题+代码!!
  5. EcmaScript 6 新特性
  6. mycat分库分表demo
  7. python igraph使用教程
  8. Matlab 小球落地问题
  9. 碳交易机制下考虑需求响应的综合能源系统优化运行
  10. 实锤!长沙智博美术培训学校