信号量与信号的区别!

信号量:内核中的一个计数器/实现进程间同步(条件判断合理性)与互斥(同一时间唯一访问安全性)。

信号:进程之间事件异步通知的一种方式,是一种软中断,非信号量。

作用:操作系统通过信号告诉进程发生了某个事件,打断进程当前的操作,去处理这个事件。

通过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代码优化相关推荐

  1. linux查看进程的内存使用情况,[转]linux下查看进程内存使用情况

    动态查看一个进程的内存使用 1.top命令 top -d 1 -p pid [,pid ...] //设置为delay 1s,默认是delay 3s 如果想根据内存使用量进行排序,可以shift + ...

  2. 查看linux进程的设备io,Linux下查看进程IO工具iopp

    Linux下的IO检测工具最常用的是iostat,不过iostat只能查看到总的IO情况.如果要细看具体那一个程序点用的IO较高,可以使用iotop .不过iotop对内核版本和Python版本有要求 ...

  3. linux下杀死进程全权讲解

    linux下杀死进程全权讲解 2009-10-27 08:57 佚名 linux 我要评论(0) 字号:T | T 本文将详细讲解linux杀死进程的多种命令,包含他们的作用,kill作用:根据进程号 ...

  4. linux下查看进程的线程数,linux查看进程的线程数

    top -H -p $PID  #查看对应进程的那个线程占用CPU过高 1.top -H 手册中说:-H : Threads toggle 加上这个选项启动top,top一行显示一个线程.否则,它一行 ...

  5. linux下僵尸进程(<defunct>进程)的产生与避免

    一.什么是僵尸进程 在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他,那么他将变成一个僵尸进程.当用ps命令观察进程的执行状态时,看到这些进程的状态栏为 ...

  6. 【Linux】从冯诺依曼体系到初识Linux下的进程

    目录 前言 1.冯诺依曼体系结构 2.管理和操作系统 3.初识进程 1.描述进程PCB(process control block) 1.标识符pid fork接口创建子进程 2.进程状态 3.进程优 ...

  7. Linux第二次试验:Linux下的进程通信实验

    Linux第二次试验:Linux下的进程通信实验 前言 一.实验目的 二.实验工具与设备 三.实验预备知识 三.实验内容和步骤 五.实验代码及步骤截图 六.实验总结 前言 为了帮助同学们完成痛苦的实验 ...

  8. linux 下得到进程的启动时间

    linux 下得到进程的启动时间! 运行方式:./pstart 进程号 " 如: ./pstart 1 #!/bin/bash pid=$1 if [ "$pid" == ...

  9. linux下查看进程占用端口和端口占用进程命令

    Linux下查看进程占用端口: 查看程序对应进程号:ps –ef|grep 进程名 REDHAT :查看进程号所占用的端口号:netstat –nltp|grep 进程号 ubuntu:查看进程占用端 ...

  10. 性能测试入门(六)windows及Linux下做压力测试的注册表设置

    windows及Linux下做压力测试的注册表设置 from: http://www.cnblogs.com/tianzhiliang/articles/2400176.html TcpTimedWa ...

最新文章

  1. R语言β分布函数(dbeta、pbeta、qbeta、rbeta)实战
  2. linux c/c++ 判断是否为中文(不包括中文符号,非正则)
  3. MATLAB编程规范
  4. 树状数组(单点+区间的所有操作)
  5. Luogu 1941 飞扬的小鸟
  6. 梅森增益matlab求解,梅森公式互不接触回路及其增益
  7. 2019蓝桥杯省赛---java---C---1(求和)
  8. mysql+磁盘i+o+优化_浅析MySQL数据库磁盘I/O调整优化 | 学步园
  9. 阶段1 语言基础+高级_1-3-Java语言高级_04-集合_08 Map集合_3_Map接口中的常用方法...
  10. 狼群ps-天空大师扩展插件_扩展OctoberCMS-构建软删除插件
  11. SQL Server数据库优化的几种方法.
  12. 利用IPC$空连接进行入侵及防范的方法
  13. LabWindows图表显示
  14. 看看最新BTA大厂的Java程序员的招聘技术标准,聪明人已经收藏了!
  15. 一个更高效的RACK机制
  16. 运维派 企业面试题1 监控MySQL主从同步是否异常
  17. Fabrice Bellard其人
  18. python 删除文件夹、删除非空文件夹
  19. QML和C++之间的数据类型转换
  20. 机器学习-鸢尾花(Iris Flower)分类

热门文章

  1. Python使用HappyBase连接Hbase与基本操作
  2. python list转dict
  3. 使用selenium爬取csdn博客
  4. 中级php工程师书籍,中级PHP工程师
  5. i9100美化android.policy.jar,摆脱越狱束缚 三星I9100安装应用更轻松
  6. linux texmaker编译,在Ubuntu下安装和编译LaTex
  7. 详解如何在vue项目中引入饿了么elementUI组件
  8. [刷题]算法竞赛入门经典(第2版) 5-2/UVa1594 - Ducci Sequence
  9. 你可能不知道console强大
  10. [转]黑盒测试和白盒测试