孤儿进程和僵尸进程

如果父进程先退出,子进程还没退出那么子进程的父进程将变为init进程。(注:任何一个进程都必须有父进程)

如果子进程先退出,父进程还没退出,那么子进程必须等到父进程捕获到了子进程的退出状态才真正结束,否则这个时候子进程就成为僵进程。

孤儿进程

如果父亲进程先结束,子进程会托孤给1号进程

父进程注册SIGCHLD信号,然后在回调函数里while (waitpid(0, NULL, WNOHANG) > 0); 注意这个分号不能少.

避免僵尸进程的另一种方法

#include <signal.h>

signal(SIGCHLD, SIG_IGN); 告诉内核,本进程要忽略SIGCHLD,请内核大哥帮忙处理.

在SIGCHLD信号被显式忽略的情况下,2.6内核子进程将直接退出并释放资源,等父进程调用waitpid时,发现对应的pid进程已不存在,因而返回-1错误,errno为10(No child processes)。
从某位高手的博客里看到了这个解释。大概就是因为显示忽略SIGCHLD信号时,内核会处理子进程的退出状态,再调用waitpid的时候,就找不到子进程了。不显示忽略的时候,内核不会对子进程的退出做处理,所以还是能找到的。至于设置了信号处理函数之后为什么还是能正常返回?我推测应该是进程同步问题。信号处理函数对这个信号的处理是异步的,所以等到空闲时,父进程才会调用这个函数来处理信号,在这之前,waitpid就已经发挥作用,所以正常返回。由于初学,所以也不太懂,还请高手指正阿!

1、wait和waitpid出现的原因

SIGCHLD

当子进程退出的时候,内核会向父进程发送SIGCHLD信号,子进程的退出是个异步事件(子进程可以在父进程运行的任何时刻终止)

子进程退出时,内核将子进程置为僵尸状态,这个进程称为僵尸进程,它只保留最小的一些内核数据结构,以便父进程查询子进程的退出状态。

父进程查询子进程的退出状态可以用wait/waitpid函数

Wait获取status后检测处理

宏定义     描述

WIFEXITED(status)  如果子进程正常结束,返回一个非零值

  WEXITSTATUS(status)      如果WIFEXITED非零,返回子进程退出码

WIFSIGNALED(status)     子进程因为捕获信号而终止,返回非零值

  WTERMSIG(status) 如果WIFSIGNALED非零,返回信号代码

WIFSTOPPED(status)       如果子进程被暂停,返回一个非零值

  WSTOPSIG(status)   如果WIFSTOPPED非零,返回一个信号代码

用来等待某个特定进程的结束

waitpid(pid_t pid, int *status,int options)

对于waitpid的p I d参数的解释与其值有关:

pid == -1 等待任一子进程。于是在这一功能方面waitpid与wait等效。

pid > 0 等待其进程I D与p I d相等的子进程。

pid == 0 等待其组I D等于调用进程的组I D的任一子进程。换句话说是与调用者进程同在一个组的进程。

pid < -1 等待其组I D等于p I d的绝对值的任一子进程。

Wait和waitpid区别和联系

在一个子进程终止前,wait 使其调用者阻塞,而waitpid 有一选择项,可使调用者不阻塞。

waitpid并不等待第一个终止的子进程—它有若干个选择项,可以控制它所等待的特定进程。

实际上wait函数是waitpid函数的一个特例。

abort() //会发出一个6号信号

会话期:是一个或者多个进程组的集合,通常一个会话期开始与用户登录,终止于用户退出。在此期间,该用户运行的所有进程都属于这个会话期。

中断

中断是系统对于异步事件的响应()

中断信号

中断源

现场信息

中断处理程序

中断向量表

异步事件的响应:进程执行代码的过程中可以随时被打断,然后去执行异常处理程序

生活中的中断和计算机系统中的中断

4)中断的其他概念

中断向量表保存了中断处理程序的入口地址。

中断个数固定,操作系统启动时初始化中断向量表。

中断有优先级(有人敲门,有人打电话,有优先级)

中断可以屏蔽(张三可以屏蔽电话)。

信号名称         描述

SIGABRT  进程停止运行 6

SIGALRM  警告钟

SIGFPE      算述运算例外

SIGHUP    系统挂断

SIGILL       非法指令

SIGINT      终端中断 2

SIGKILL     停止进程(此信号不能被忽略或捕获)

SIGPIPE    向没有读者的管道写入数据

SIGSEGV  无效内存段访问

SIGQUIT   终端退出3

SIGTERM 终止

SIGUSR1  用户定义信号1

SIGUSR2  用户定义信号2

SIGCHLD  子进程已经停止或退出

SIGCONT 如果被停止则继续执行

SIGSTOP   停止执行

SIGTSTP   终端停止信号

SIGTOUT  后台进程请求进行写操作

SIGTTIN   后台进程请求进行读操作

进程对信号的三种相应

忽略信号

不采取任何操作、有两个信号不能被忽略:SIGKILL(9号信号)和SIGSTOP。

思考1:为什么进程不能忽略SIGKILL、SIGSTOP信号。(如果应用程序可以忽略这2个信号,系统管理无法杀死、暂停进程,无法对系统进行管理。)。SIGKILL(9号信号)和SIGSTOP信号是不能被捕获的。

捕获并处理信号

内核中断正在执行的代码,转去执行先前注册过的处理程序。

执行默认操作

默认操作通常是终止进程,这取决于被发送的信号。

signal信号安装函数

函数原型:__sighandler_t signal(intsignum, __sighandler_t handler);

返回值,如果成功则返回信号以前的行为

不可靠信号PK可靠信号

不可靠信号是前32个信号,不支持排队.在快速发送时可能会造成丢失,因为在进程PCB控制的信号未决信号集,是不能排队的,多个同种信号的到来,只会有一个同种信号在未决集.

可靠信号

随着时间的发展,实践证明,有必要对信号的原始机制加以改进和扩充。所以,后来出现的各种unix版本分别在这方面进行了研究,力图实现"可靠信号"。由于原来定义的信号已有许多应用,不好再做改动,最终只好又新增加了一些信号,并在一开始就把它们定义为可靠信号,这些信号支持排队,不会丢失。同时,信号的发送和安装也出现了新版本:信号发送函数sigqueue()及信号安装函数sigaction()。

sleep函数几点说明

1)sleep函数作用,让进程睡眠。

2)能被信号打断,然后处理信号函数以后,就不再睡眠了。直接向下执行代码

3)sleep函数的返回值,是剩余的秒数

raise

raise

给自己发送信号。raise(sig)等价于kill(getpid(), sig);

killpg

给进程组发送信号。killpg(pgrp, sig)等价于kill(-pgrp, sig);

sigqueue

给进程发送信号,支持排队,可以附带信息。

pause()函数

将进程置为可中断睡眠状态。然后它调用内核函数schedule(),使linux进程调度器找到另一个进程来运行。

pause使调用者进程挂起,直到一个信号被捕获

alarm函数,设置一个闹钟延迟发送信号

告诉linux内核n秒中以后,发送SIGALRM信号;;

可重入函数概念

为了增强程序的稳定性,在信号处理函数中应使用可重入函数。

所谓可重入函数是指一个可以被多个任务调用的过程,任务在调用时不必担心数据是否会出错。因为进程在收到信号后,就将跳转到信号处理函数去接着执行。如果信号处理函数中使用了不可重入函数,那么信号处理函数可能会修改原来进程中不应该被修改的数据,这样进程从信号处理函数中返回接着执行时,可能会出现不可预料的后果。不可再入函数在信号处理函数中被视为不安全函数。

满足下列条件的函数多数是不可再入的:(1)使用静态的数据结构,如getlogin(),gmtime(),getgrgid(),getgrnam(),getpwuid()以及getpwnam()等等;(2)函数实现时,调用了malloc()或者free()函数;(3)实现时使用了标准I/O函数的

信号在内核中的表示

执行信号的处理动作称为信号递达(Delivery),信号从产生到递达之间的状态,称为信号未决(Pending)。

进程可以选择阻塞(Block)某个信号。被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。

画图

当一个信号发送给一个进程时,进程控制块pcb控制着这个信号的走向,未决集(只可读,不可写),阻塞集(可读可写)都是64位数,因为有64个信号,每个位对应一个信号,一个信号要通过这两个集才能抵达

未决集初始状态全为0,信号首先进入到未决集,未决集的相应位变成1,然后查看阻塞位,如果阻塞位是1,那么信号无法通过,就一直在未决集,此时叫做未决态,一旦阻塞位变成0了,信号马上通过,未决集还没有变成0,

信号最后由程序决定如何处理(忽略,捕捉,默认行为),处理时未决集变成0,可以接收新的信号.

在信号处理函数中对某个信号进行解除阻塞时,则只是将pending位清0

信号集操作函数(状态字表示)

#include <signal.h>

intsigemptyset(sigset_t *set);把信号集清空 64bit/8=8个字节   sigset_t是一个64位的数

intsigfillset(sigset_t *set);把信号集全填写成1

intsigaddset(sigset_t *set, intsigno);根据signo,把信号集中的对应为置成1

intsigdelset(sigset_t *set, intsigno);根据signo,把信号集中的对应为置成0

intsigismember(constsigset_t *set, intsigno);//判断signo是否在信号集中

sigprocmask读取或更改进程的信号屏蔽状态字(block)

#include <signal.h>

int sigprocmask(int how, const sigset_t *set, sigset_t *oset);

功能:读取或更改进程的信号屏蔽字。

返回值:若成功则为0,若出错则为-1

sigpending获取信号未决状态字(pending)信息

#include <signal.h>

int sigpending(sigset_t *set);

sigaction函数

信号注册函数,与signal一样,只不过功能更加强大.

int sigaction(int signum,const struct sigaction *act,const struct sigaction *old);

sigaction结构体

第二个参数最为重要,其中包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程中应屏蔽掉哪些函数等等

structsigaction {

void (*sa_handler)(int);   //信号处理程序不接受额外数据

void (*sa_sigaction)(int, siginfo_t *, void *); //信号处理程序能接受额外数据,和sigqueue配合使用

sigset_t sa_mask; //信号处理函数执行的过程中阻塞哪些信号 sa_mask类型与未注册的信号集一样.但不需要sigprocmask

int sa_flags; //影响信号的行为SA_SIGINFO表示能接受数据

void (*sa_restorer)(void); //废弃

};

注意1:回调函数句柄sa_handler、sa_sigaction只能任选其一。

 

sigqueue新的信号发送函数,功能更强大.

    struct sigaction act;
union sigval mysigval; mysigval.sival_int = 111;
sigemptyset(&act.sa_mask); //信号处理过程中不阻塞其它信号,
act.sa_flags = SA_SIGINFO; //表示发送数据外加新的内容
act.sa_sigaction = msigaction; //回调函数赋值
sigaction(SIGINT, &act, NULL); //注册信号 sigqueue(getpid(), SIGINT, mysigval); //发送信号

  

sigqueue()比kill()传递了更多的附加信息,但sigqueue()只能向一个进程发送信号,而不能发送信号给一个进程组。

linux第2天 信号 wait的更多相关文章

  1. Linux环境进程间通信(二): 信号(上)

    linux下进程间通信的几种主要手段: 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允 ...

  2. 自学Linux Shell15.1-处理信号

    点击返回 自学Linux命令行与Shell脚本之路 15.1-处理信号 Linux使用信号与系统上运行的进程进行通信.可以使用这些信号控制Shell脚本的运行,只需要让shell脚本在接收到来自Lin ...

  3. linux系统编程之信号(一):中断与信号

    一,什么是中断? 1.中断的基本概念 中断是指计算机在执行期间,系统内发生任何非寻常的或非预期的急需处理事件,使得CPU暂时中断当前正在执行的程序而转去执行相应的事件处理程序,待处理完毕后又返回原来被 ...

  4. Linux内核中的信号机制--一个简单的例子【转】

    本文转载自:http://blog.csdn.net/ce123_zhouwei/article/details/8562958 Linux内核中的信号机制--一个简单的例子 Author:ce123 ...

  5. linux下的常见信号总结

    在linux下有很多信号,按可靠性分为可靠信号和非可靠信号,按时间分为实时信号和非实时信号,linux进程也有三种方式来处理收到的信号: (1)忽略信号,即对信号不做任何处理,其中,有两个信号不能忽略 ...

  6. Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存

    Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存 参考:<linux编程从入门到精通>,<Linux C程序设计大全>,<unix环境高级编程> ...

  7. [转]Linux下的常见信号总结

    转自 https://www.cnblogs.com/gaorong/p/6430905.html 在linux下有很多信号,按可靠性分为可靠信号和非可靠信号,按时间分为实时信号和非实时信号,linu ...

  8. linux中的常用信号

    linux中的常用信号,见如下列表: 信号名 值 标注 解释 ------------------------------------------------------------------ HU ...

  9. Linux signal 常见的信号含义表

    http://blog.csdn.net/xgjianstart/article/details/4544418 通过命令 kill -l  可查看全部信号 SIGHUP 终止进程 终端线路挂断 本信 ...

  10. Linux学习 :按键信号 之 异步通知

    一.异步通知概念: 异步通知是指:一旦设备就绪,则主动通知应用程序,应用程序根本就不需要查询设备状态,类似于中断的概念,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的.信号是异步的,一个进 ...

随机推荐

  1. [daily][CentOS][yum] 删除包的同时一同清理掉安装时一起装进来的依赖包

    说起来有点绕口,这个需求是这样的. 就是我yum装A包的时候,同时安装了A的依赖包a1,a2,a3. 当我们使用yum remove A卸载A包的是,a1,a2,a3包并不会一同被卸载掉.如果他们没有 ...

  2. BlueDroid代码分析之GKI

    目录 1. 概述 2. 线程 2.1 主要函数 2.2 功能 3. 事件 3.1 主要函数 3.2 功能 1. 概述 GKI以库libbt-brcm_gki.so(Static Lib?)的形式提供给 ...

  3. php源码安装

    要用swoole,首先需要有PHP环境.由于swoole的某些特性,最好是能够从源码编译安装PHP,这样在使用过程中可以避免很多不必要的错误.PHP下载地址:http://php.net/在这里挑选你 ...

  4. Object C语法学习笔记(一)

    1.@property与@synthesize配对使用. @property预编译指令的作用是自动声明属性的setter和getter方法. @synthesize 创建了该属性的访问代码 功能:让编 ...

  5. CheckedListBoxControl 使用

    绑定用法 StringBuilder sb = new StringBuilder(); sb.AppendFormat("select id, filename, addtime from ...

  6. css spprite应用

    (一)实现简单的淘宝带图标侧边栏效果 <!DOCTYPE html> <html lang="en"> <head> <meta char ...

  7. Android开发笔记:打包数据库

    对于数据比较多的控制一般会加入SQLite数据库进行数据存储,在打包时这些数据库是不自动打包到apk中的,如何创建数据库呢 方法1:将创建数据库的sql语句在SQLiteHelper继承类中实现,在第 ...

  8. ios UIPickerView 技巧集锦(包括循环滚动)

    摘自: http://blog.csdn.net/ipromiseu/article/details/7436521 http://www.cnblogs.com/dabaopku/archive/2 ...

  9. 关于ajax的异步通信之异步

    我有这样一个js函数 function add (){ $ajax({ url:"xxxxxx", data:""xxxxx", dataType:& ...

  10. Keep Alive

    跳板机时经常出现连接被断开的情况.如果发生这种情况,请在客户端配置Keep Alive设置,具体方法参考如下: Windows: secureCRT:Properties -> Terminal ...