linux笔记之初次接触信号
来源:互联网 发布:mac优酷缓存视频路径 编辑:程序博客网 时间:2024/06/03 12:19
一.关于信号概念
1.信号是Linux所使用的进程间通信的最古老的方式。它是在软件层次上对中断机制的一种模拟,是一种异步通信的方式 。一个完整的信号周期包括三个部分,信号的产生,信号在进程中的注册,信号在进程中的注销,执行信号处理函数。如下图所示:
这里的对信号产生注册和注销都是信号的内部机制,而不是信号函数完成的
2.对信号的处理动作有三种:
a. 忽略此信号
b.执行该信号的默认处理动作
c.捕捉信号(自由态)
3.查看系统定义中的信号列表: kill -l 命令。
每个信号都有一个编号和一个宏定义名称,这些宏定义名称可以在signal.h中找到,例如:其中有定义#define SIGINT 2
二.产生信号
1. 通过终端按键产生信号
如下代码:
#include<stdio.h>#include<signal.h>void hander(int sig){ printf("%d\n",sig);}int main(){ signal(2,hander); while(1) { printf("i am a proc\n"); sleep(1); }}
以上代码使用了signal函数用来捕捉信号,则可以说明的是:ctrl+c实现的是信号的2号信号SIGINT。
2.调用系统函数向进程发信号
介绍几个函数
- kill命令是调用kill函数实现的。kill函数可以给一个指定的进程发送指定的信号。
#include<signal.h>int kill(pid_t pid,int signo);
- raise函数可以给当前进程发送指定的信号(自己给自己发信号)
#include<signal.h>int raise(int signo);
如下两个代码实现raise函数的功能:
#include<stdio.h>#include<signal.h>#include<sys/types.h>#include<stdlib.h>void hander(int sig){ printf("%d\n",sig);}int main(){ signal(2,hander); sleep(3); while(1) { raise(2); printf("i am a proc\n"); sleep(1); }}
结果如下图:
#include<stdio.h>#include<signal.h>#include<sys/types.h>#include<stdlib.h>void hander(int sig){ printf("%d\n",sig);}int main(){ signal(2,hander); sleep(3); raise(2); while(1) { printf("i am a proc\n"); sleep(1); }}
结果如下图:
- abort函数可以使当前进程接收到信号而异常终止,像exit函数一样,abort函数总会成功,故无返回值
#include<stdlib.h>void abort(void);
3.由软件条件产生信号
例如:模拟闹钟
调用alarm函数可以设定一个闹钟,告诉内核在seconds秒之后给当前进程发SIGALRM信号,该信号的默认动作是终止当前程序
该函数的返回值是0或者是以前设定的闹钟时间还余下的秒数
用以下代码实现alarm的功能:
代码1:
#include<stdio.h>#include<unistd.h>int main(){ alarm(1); int count=0; for(;1;count++) { printf("count= %d\n",count); } return 0;}
结果示意图:
###代码2:
#include<stdio.h>#include<signal.h>#include<sys/types.h>#include<stdlib.h>#include<unistd.h>int count=0;void hander(int sig){ printf("count = %d\n",count);}int main(){ signal(14 ,hander); alarm(1); while(1) { count++; } return 0;
结果示意图:
以上两个代码均是表示count 在1 秒累加的次数,从结果看出第二个数比第一个数大很多,所以说明输入输出流对计算的速度影响非常大
三.阻塞信号
1. 信号在内核中的表示
a.实际执行信号的处理动作叫信号递达(Delivery),信号从产生到递达的状态,称为信号未决(Pending).进程可以选择阻塞某个信号。
b.信号阻塞就不会被递达,除非信号先被未决,然后解除阻塞。
c.信号在那内核中的表示示意图:
2.信号集操作函数
#include<signal.h>int sigemptyset(sigset_t *set);//初始化set所指向的信号集,使其所有的bit清零,表示该信号集不包含任何有效信号。int sigfillset(sigset_t *set);//初始化set所指向的信号集int sigaddset(sigset_t *set,int signo);//在信号集中添加某种信号int sigdelset(sigset_t *set,int signo);//在信号集中删除某种信号int sigismemset(const sigset_t *set,int signo);//是一个布尔函数,用于判断一个信号集的有效信号中是否包含某种信号,包含返回1,反之返回0;
3.sigprocmask
#include<signal.h>int sigprocmask(int how,const sigset *set,sigset_t *oset);//可以读取和改进进程的信号屏蔽字(阻塞信号集)
4.sigpending
#include<signal.h>int sigpending(sigset_t *set);//读取当前进程的未决信号集,通过set参数传出
使用以上函数模拟一个信号在内核中的表示
#include<stdio.h>#include<signal.h>#include<unistd.h>void show(sigset_t* pending){ int i=1; for(; i<32; i++) { if(sigismember(pending,i)) { printf("1 "); } else { printf("0 "); } } printf("\n");}int main(){ sigset_t block; sigset_t oblock; sigemptyset(&block); sigemptyset(&oblock); sigfillset(&block); sigfillset(&oblock); sigaddset(&block,2); sigprocmask(SIG_BLOCK,&block,&oblock); sigprocmask(SIG_BLOCK,&oblock,NULL); while(1) { sigpending(&block); show(&block); sleep(1); } return 0;}
结果示意图:
程序运行时候,每秒钟都把各个信号的未决状态打印一遍,由于我们阻塞了SIGINT信号,故按CTRL+C将会使SIGINT信号处于未决状态,按CTRL+\则可以终止程序,因为SIGQUIT信号没有被阻塞。
1 0
- linux笔记之初次接触信号
- 初次接触linux 总结:
- 【学习笔记之Openlayers3】初次接触openlayers3(第一篇)
- 初次接触linux系统编程
- UGUI初次接触之Canvas
- zigbee学习笔记4----初次接触zstack
- zigbee学习笔记4----初次接触zstack
- xUtils初次接触及个人理解笔记
- linux杂谈(十):初次接触selinux
- 初次接触Linux,发展历程和介绍
- 初次接触Linux、Unix>特点、对比
- 初次接触嵌入式系统和linux
- linux学习笔记之信号
- 初次接触
- 初次接触
- 初次接触
- 成员函数指针之初次接触
- nrf51822学习之BLE400初次接触
- OpenCV分水岭算法中标记图的妙用
- C++对象模型 学习笔记01
- spark的集群管理器
- 概念了解:(三)OLTP、OLAP
- porting MPTCP to LineageOS-14.1-kiwi
- linux笔记之初次接触信号
- C++ Primer(第五版)练习3.32
- 杭电oj 1004 Let the Balloon Rise
- leetcode92. Reverse Linked List II
- 209. Minimum Size Subarray Sum LeetCode
- Linux进程管理之task_struct结构体详解
- Java——带参方法
- porting MPTCP to LineageOS-14.1-kiwi
- 若干个不同的自然和为定值,这些自然数乘积最大为多少?