linux下的进程信号,信号注册、处理方式、注销,信号阻塞及volatile代码优化
信号量与信号的区别!
信号量:内核中的一个计数器/实现进程间同步(条件判断合理性)与互斥(同一时间唯一访问安全性)。
信号:进程之间事件异步通知的一种方式,是一种软中断,非信号量。
作用:操作系统通过信号告诉进程发生了某个事件,打断进程当前的操作,去处理这个事件。
通过kill -l命令查看系统中的信号种类-62种。
1~31号信号:从unix借鉴来,每个信号都有具体对应的系统事件,---非可靠信号(可能丢失-事件丢失)
34~64号信号:后期扩充,没有具体事件,---可靠信号(不会丢失)
信号的生命周期:产生->在进程中注册->进程中注销->处理。
产生:
硬件:ctrl+c/ctrl+z/
软件:kill命令发送信号,kill-9强杀,kill -signum pid命令,kill(int pid,int signum)给指定接口发送信号/raise(int signum)/abort()/alarm(int seconds)
原理:kill杀死一个进程,向进程发送一个信号,信号有对应的事件,进程放下手头工作去处理事件,事件的处理结果就是进程退出。
命令fg 1功能是将一个后台作业调到前台运行。
信号在进程(pcb)中注册:如何让进程知道自己收到了某个信号;pcb->struct sigpending->struct sigset_t,就是修改位图,还会为信号组织一个sigqueue节点添加到pcb的sigqueue链表中--称为未决信号集合--收到了但是没有被处理的信号集合。
sigset_t这个结构体只有一个数组成员,这个数组用于实现一个位图,给一个进程发送一个信号,就会将这个位图中对应位置1,表示进程当前收到了这个信号;
位图只有0/1状态,只表示是否收到信号,无法表示收到多少个信号。
1~31非可靠信号注册:若信号注册的时候位图为0,则会创建一个sigqueue节点并修改位图为1,若位图为1,则什么都不做
34~64可靠信号注册:无论位图当时是都为0,都会创建一个节点,添加到链表中,并修改位图。
信号在进程中注销:为了保证一个信号只会被处理一次,因此先注销再处理;在pcb中删除当前信号信息;将pending位图置0;删除信号节点;
非可靠信号注销:因为非可靠信号只会有一个节点,因此删除节点后,位图直接置0;
可靠信号注销:可注册多次,有多个节点,在删除节点后,需要判断是否还有相同节点,若无才会位图置0。
信号的处理:信号表示一个事件的到来,处理事件就是完成功能,在C语言中完成一个功能的最小模块--函数。
信号的处理方式:
1.默认处理方式:操作系统中原定义好的每个信号的处理方式
2.忽略处理方式:处理方式就是忽略,什么都不做。
3.自定义处理方式:自己定义一个事件函数,使用这个函数替换内核中默认的处理函数;信号到来就会调用我们定义的函数了。
接口:
typedef void (*sighandler_t)(int);//类型重定义--定义一个名称为sighandler_t函数指针类型
sighandler_t signal(int signum, sighandler_t handler);
handler:SIG_DFL--默认处理方式 /SIG_IGN--忽略处理方式 /用户自己定义一个无返回值,有int型参数的函数地址。
信号捕捉:signal
如何阻塞一个信号:
int sigprocmask(int how,sigset_t *set,sigset_t *old);
how:
SIG_BLOCK(相当于set|block)--将set集合中的信号添加到内核中的block阻塞信号集合中,使用old保存原来的阻塞信息以便于还原。---阻塞set集合中的信号。
SIG_UNBLOCK(相当于~set&block)--将set集合中的信号从内核中的block阻塞信号集合中移除--对set集合中的信号解除阻塞。
SIG_SETMASK(相当于set=block赋值)--将内核中的block阻塞信号集合内容设置为set集合中的信息--阻塞set集合中的信号。
1.将所有信号都给阻塞;2.在解除阻塞之前,给进程发送信号;3.解除阻塞,查看信号的处理情况
int sigemptyset(sigset_t *set);//清空set信号集合--使用一个变量初始化过程
int sigaddset(sigset_t *set, int signum);//向set集合中添加指定的信号
int sigfillset(sigset_t *set)//将所有信号添加到set集合中
int sigdelset(sigset_t *set, int signum);//从set集合中移除指定信号
int sigismember(const sigset_t *set, int signum);//判断指定信号是否在set集合中
代码如下:
结果如下:
可靠信号被创建了6次,非可靠信号就注册了一次。
所有信号中,两个信号比较特殊:SIGKILL -9/SIGSTOP -19,这两个信号不可被阻塞,不可被忽略,不可被自定义。可通过kill -l查看信号。
僵尸进程:子进程退出后会向父进程发送SIGCHLD信号通知父进程,子进程的状态改变。
如何处理僵尸进程为非僵尸进程?
但是因为SIGCHLD信号默认的处理方式是忽略;因此之前的程序若不进行进程等待则不知道进程的退出;
如果要进程等待,而且还不想让父进程阻塞,就可以自定义SIGCHLD信号的处理方式;在自定义回调函数中调用waitpid,处理僵尸进程,父进程就不用一直等待。
但是SIGCHLD信号是一个非可靠信号,如果有多个子进程同时退出,有可能造成信号丢失。
while(waitpid(-1,NULL,WNOHANG)>0);非阻塞循环在一个回调中将所有的僵尸进程全部处理。
waitpid(int pid,int *status,int options)
options: WNOHANG--将waitpid设置为非阻塞,没有子进程退出则立即报错返回。
0--默认阻塞等待子进程退出
返回值:>0 退出子进程的pid;
==0有子进程但没有退出
<0出错了(例如当前无子进程)
关键字volatile:用于修饰一个变量,保持变量的内存可见性(cpu在处理的时候每次都重新从内存获取数据),防止编译器过度优化。
cpu处理一个数据时从内存中将数据加载到寄存器上进行处理
gcc编译器在编译程序时,若使用了代码优化 -Olevel选项,发现某个变量使用频率非常高,为了提高效率,则直接将变量的值设置为某个寄存器的值,以后访问的时候直接从寄存器访问,则减少了内存访问的过程,提高了效率。但是这种优化有时候会造成代码的逻辑混乱。
因此使用volatile关键字修饰变量,让cpu无论如何每次都重新到内存中获取数据。
代码优化相当于:原先访问数据的地址,通过地址找到数据,代码优化不访问地址,直接将数据放入内存。
函数的重入:在多个执行流程中,同时进入一个函数运行。
函数可重入:指的是函数重入后,不会造成数据二义或者逻辑混乱。
函数不可重入:指的是函数重入之后,有可能造成数据二义或者逻辑混乱。
函数是否可重入的判断基准:这个函数中是否对全局变量进行了非原子操作。
操作的原子性:操作一次完成,中间不会被打断。
原子操作:操作要么一次完成,要么不做。
一个函数若根本没有操作全局数据,则肯定是可重入的,因为每个函数调用的时候都有独立的函数栈
一个函数若对全局数据进行了操作,但是操作是原子性的,则也是可重入的。
linux下的进程信号,信号注册、处理方式、注销,信号阻塞及volatile代码优化相关推荐
- linux查看进程的内存使用情况,[转]linux下查看进程内存使用情况
动态查看一个进程的内存使用 1.top命令 top -d 1 -p pid [,pid ...] //设置为delay 1s,默认是delay 3s 如果想根据内存使用量进行排序,可以shift + ...
- 查看linux进程的设备io,Linux下查看进程IO工具iopp
Linux下的IO检测工具最常用的是iostat,不过iostat只能查看到总的IO情况.如果要细看具体那一个程序点用的IO较高,可以使用iotop .不过iotop对内核版本和Python版本有要求 ...
- linux下杀死进程全权讲解
linux下杀死进程全权讲解 2009-10-27 08:57 佚名 linux 我要评论(0) 字号:T | T 本文将详细讲解linux杀死进程的多种命令,包含他们的作用,kill作用:根据进程号 ...
- linux下查看进程的线程数,linux查看进程的线程数
top -H -p $PID #查看对应进程的那个线程占用CPU过高 1.top -H 手册中说:-H : Threads toggle 加上这个选项启动top,top一行显示一个线程.否则,它一行 ...
- linux下僵尸进程(<defunct>进程)的产生与避免
一.什么是僵尸进程 在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他,那么他将变成一个僵尸进程.当用ps命令观察进程的执行状态时,看到这些进程的状态栏为 ...
- 【Linux】从冯诺依曼体系到初识Linux下的进程
目录 前言 1.冯诺依曼体系结构 2.管理和操作系统 3.初识进程 1.描述进程PCB(process control block) 1.标识符pid fork接口创建子进程 2.进程状态 3.进程优 ...
- Linux第二次试验:Linux下的进程通信实验
Linux第二次试验:Linux下的进程通信实验 前言 一.实验目的 二.实验工具与设备 三.实验预备知识 三.实验内容和步骤 五.实验代码及步骤截图 六.实验总结 前言 为了帮助同学们完成痛苦的实验 ...
- linux 下得到进程的启动时间
linux 下得到进程的启动时间! 运行方式:./pstart 进程号 " 如: ./pstart 1 #!/bin/bash pid=$1 if [ "$pid" == ...
- linux下查看进程占用端口和端口占用进程命令
Linux下查看进程占用端口: 查看程序对应进程号:ps –ef|grep 进程名 REDHAT :查看进程号所占用的端口号:netstat –nltp|grep 进程号 ubuntu:查看进程占用端 ...
- 性能测试入门(六)windows及Linux下做压力测试的注册表设置
windows及Linux下做压力测试的注册表设置 from: http://www.cnblogs.com/tianzhiliang/articles/2400176.html TcpTimedWa ...
最新文章
- R语言β分布函数(dbeta、pbeta、qbeta、rbeta)实战
- linux c/c++ 判断是否为中文(不包括中文符号,非正则)
- MATLAB编程规范
- 树状数组(单点+区间的所有操作)
- Luogu 1941 飞扬的小鸟
- 梅森增益matlab求解,梅森公式互不接触回路及其增益
- 2019蓝桥杯省赛---java---C---1(求和)
- mysql+磁盘i+o+优化_浅析MySQL数据库磁盘I/O调整优化 | 学步园
- 阶段1 语言基础+高级_1-3-Java语言高级_04-集合_08 Map集合_3_Map接口中的常用方法...
- 狼群ps-天空大师扩展插件_扩展OctoberCMS-构建软删除插件
- SQL Server数据库优化的几种方法.
- 利用IPC$空连接进行入侵及防范的方法
- LabWindows图表显示
- 看看最新BTA大厂的Java程序员的招聘技术标准,聪明人已经收藏了!
- 一个更高效的RACK机制
- 运维派 企业面试题1 监控MySQL主从同步是否异常
- Fabrice Bellard其人
- python 删除文件夹、删除非空文件夹
- QML和C++之间的数据类型转换
- 机器学习-鸢尾花(Iris Flower)分类
热门文章
- Python使用HappyBase连接Hbase与基本操作
- python list转dict
- 使用selenium爬取csdn博客
- 中级php工程师书籍,中级PHP工程师
- i9100美化android.policy.jar,摆脱越狱束缚 三星I9100安装应用更轻松
- linux texmaker编译,在Ubuntu下安装和编译LaTex
- 详解如何在vue项目中引入饿了么elementUI组件
- [刷题]算法竞赛入门经典(第2版) 5-2/UVa1594 - Ducci Sequence
- 你可能不知道console强大
- [转]黑盒测试和白盒测试