"===信号========================================================================================================================"
一.信号的概念:
.本质:
软中端;信号通过内核发送,内核处理的。
.特性:
)简单,)不能携带大量信息; )满足某一条件
.信号机制:
软中端;信号通过内核发送,内核处理的;通过软件的方法实现的,有较强的延迟性。 .四要素:
.信号编号, .信号名称, 。默认处理动作,.对应的事件。 .信号的默认处理动作(5种):
.终止进程(term);.忽略(Ign:信号被处理丢弃);.终止进程并产生core文件(core);
.Stop(暂停); .Cont (继续); .名词称呼
.信号的状态:
.产生;
.未决:处于产生和递达中间,由于阻塞不能递达、处理。
.递达;信号递达后内核会立即处理。(也就是说,他俩经常绑定在一起,信号递达就代表这信号被处理。)
.处理:(信号必须递达)
.忽略处理(信号已经处理,丢弃操作); .执行默认操作, .捕捉(不执行默认操作,来指定操作让其执行;) .未决信号集:(pending)
在PCB中,以位图的方式存在。
记录信号是否被产生,并且被处理。 内核处理信号的依据。用户不能直接修改未决信号集。 .阻塞信号集/信号屏蔽字:(mask)
在PCB中,以位图的方式存在。 mask影响pending;用户只可以通过mask来影响pending。
记录信号是否被设置屏蔽。用户影响信号的依据。 . - 号信号,常规信号(不支持排队); - 号信号,实时信号(支持排队) .特殊信号:(两个);
号、 号信号;不允许捕捉,忽略,甚至不能设置屏蔽。 .产生断错误的方式(三种);
.访问非访问区域。0x1000 printf(); mmu---没有映射该虚拟内存
.对只读区域进行写操作。 char* p = hello; p[] = 'H'; mmu---映射的虚拟内存对应的物理内存权限不足。 内核权限; 用户权限
.内存溢出; char buf[]; buf[] = ''; buf[] = ''; mmu---没有映射该虚拟内存。 二.产生信号:
.常见的产生信号方法:
.按键产生:ctrl+c;
.系统调用:如kill
kill(pid_t pid, int sig); 向指定进程或进程组发送指定信号;
第一个参数: pid > ; 向指定进程发送指定信号; pid == ; 向调用kill函数的进程组的所有进程发送该信号
pid == -; 发送信号给系统中有权限的所有进程; pid < -; 发送信号给指定的进程组|pid|;
第二个参数: 信号。(不同的平台环境下,信号的编号不同;但是信号的宏定义相同,所以一般使用宏名)。 raise() 给当前进程发送指定信号;
abort() 向当前进程发送SIGABRT信号;
.软件条件产生:如,定时器alarm;
alarm:每个进程有且只有唯一一个定时器。
返回值特殊:上次定时剩余的时间。定时(采用自然定时),与进程状态无关!!!,无论处于何种状态,都会计时。;
取消闹钟: alarm(); 实际执行时间 = 系统时间+用户时间+等待时间。
定时的单位是:秒。
setitimer(); 定时单位单位:微妙;
三个参数: .硬件异常产生:如,非法内存访问(段错误);内存对齐出错(总线错误);除0(浮点数除外)。
.命令产生:如kill命令 三。信号操作函数;
.信号集 set:
sigset_t set; sigemptyset(&set) 清空集合 sigfillset(&set) 置1集合 sigaddset(&set, 待添加的信号名称) 添加信号到集合中 sigdelset(&set, 待删除的信号名称) 删除信号到集合中 sigismember(&set, 待判断的信号名称)判断信号是否在集合中 -- 》 :在 :不在; -;错 .mask(信号屏蔽字/阻塞信号集)操作
sigprocmask();用来屏蔽信号、解除信号;其本质是读取或修改进程的信号屏蔽字(PCB中);
"注意:屏蔽信号只是将信号处理延后执行(延至解除屏蔽), 而忽略表示将信号丢弃。"
参数:第一个参数 how 的取值:假设当前的信号屏蔽字为mask;
.SIG_BLOCK:当how设置为此时,set表示要屏蔽的信号。相当于mask= mask|set;
.SIG_UNBLOCK:当how 设置为此时,set 表示要解除的信号。相当于:mask = mask & ~set;
.SIG_SETMASK; 当how 设置为此时,set = mask;
第二个参数: set 传入参数:用来操作mask的set集合。
第三个参数: oldset 传出参数。记录旧有的mask状态。 .pending操作
int sigpending(sigset_t *set);传出参数
参数:获取未决信号集
返回值:存在返回 ; 不存在返回 ; 四。信号捕捉
.signal:(注册信号的捕捉处理函数)
参数:.信号编号 .捕捉后调用的执行函数(是一个函数指针。即回调函数);
返回值:捕捉的函数句柄。 .sigaction: )信号捕捉函数执行期间,本信号被自动屏蔽(取决于:sa_flags) )信号捕捉函数执行期间,信号多次产生,只记录一次。 函数原型:int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
参数解析: )第一个参数:信号名称或编号;要捕捉的信号。
)第二个参数:新处理动作传入,是一个结构体。
)sa_handler: )函数指针,捕捉信号后执行的回调函数;) SIG_IGN 表示忽略; )SIG_DFL 表示执行默认操作。
)sa_mask; 信号屏蔽字/阻塞信号集;捕捉函数执行期间的屏蔽字,此中的信号在捕捉函数执行期间自动屏蔽。
)sa_flags: ) ; 表示:信号捕捉函数执行期间,要捕捉的信号被自动屏蔽(即第一个参数)。
)SA_SIGINFO: 选用sa_sigaction来指定捕捉函数;
)SA_INTERRUPT: 系统调用被信号中断后,不重启;
)SA_REATART: 系统调用被信号中断后,自动重启。
)SA_NODEFER: 在捕捉函数执行期间不自动屏蔽捕捉的信号; ) sa_sigaction: 函数指针, 三个参数,void (*sa_sigaction)(int, siginfo_t*, void*);指定带参数的信号捕捉函数。
)第三个参数:旧处理动作传出;
返回值: 表示成功, - 表示失败,并设置errno ;
.信号捕捉特性:
)捕捉函数执行期间,屏蔽字由sa_mask指定。
)捕捉函数执行期间,被捕捉的信号自动屏蔽; 由sa_flags = 决定;
)"捕捉函数执行期间,常规信号不支持排队,多次产生只记录一次。"
常规信号为:- 信号; 实时信号为 - 信号。
详细过程:进程正常运行时,默认PCB中有一个信号屏蔽字,假定为☆,它决定了进程自动屏蔽哪些信号。当注册了某个信号捕捉函数,捕捉到该信号以后,
要调用该函数。而该函数有可能执行很长时间,在这期间所屏蔽的信号不由☆来指定。而是用sa_mask来指定。调用完信号处理函数,再恢复为☆。 .信号内核实现捕捉函数思想:
信号捕捉函数是 回调函数; 由内核在信号产生、递达之后负责回调。
调用结束应该返回内核空间,再返回用户空间。 .内核实现信号捕捉的一般过程
)回调捕捉函数; )调用结束先返回内核。 “注意:此处加图片:”
五。竟态条件(时序竟态)
.pause() 函数:主动造成进程挂起,等待信号唤醒。调用该系统调用的进程将处于阻塞状态(主动放弃CPU),知道有信号到达将其唤醒。
int pause(void); 返回值:-,并设置errno == EINTR;
注意:
) 唤醒pause()函数的信号不能执行默认操作、忽略、屏蔽。原因:
)如果信号的默认动作是终止进程,则进程终止,pause函数不会有机会被调用。
)如果信号默认动作是忽略、屏蔽,则进程继续挂起,pause不会调用。
)如果信号的处理动作是捕捉,则【捕捉函数处理完后,pause被调用返回-,并且errno == EINTR,表示被信号终端,即唤醒】;
)综上所诉:能唤醒pause()函数的信号,只能是被捕捉的信号; .时序竟态:
.时序问题产生的原因: )系统负载严重; ) 信号不可靠机制; .解决时序问题:
)使用原子操作;将解除信号屏蔽与挂起等待合并成一个步骤。sigsuspend() 函数具有这个功能。在对时序要求严格的场合下都应用
sigsuspend 替换 pause。"(解除信号屏蔽+挂起等待信号)----》原子操作---》sigsuspend()函数"
int sigsuspend(const sigset_t *mask); 挂起等待信号。
函数详解: )主动造成进程挂起,等待信号; )在这个函数调用期间屏蔽字由它的参数决定; )函数调用结束屏蔽字恢复为原值;)原子操作
)提早预见,主动规避。这种错误,没法用gdb调试出来。 .全局变量的异步IO:
存在的问题:
.多个进程对 同一 个全局变量进行写操作,存在问题。(如:信号回调函数中的全局变量和主函数中的全局变量为同1个,内核进程和主进程都对
全局变量进行了写操作,非常容易出问题)。
.写操作时没有任何 同步 机制。 “注意:此处有代码,父子进程数数,代码1,主进程和内核对同一个全局变量进行写操作,出问题;
代码2,全局变量只由主进程进行一次赋值操作后,主进程和内核进程对它的只读操作,没有出问题” .可重入、不可重入函数:
注意:
)不可重入函数:函数内部含有全局变量、静态变量,使用malloc、free;
"2)信号捕捉函数应设计为可重入函数;(与上面的相反的就是可重入函数)。"
)信号处理程序调用的可重入的系统调用函数;可参阅 man signal;
)没有包含在上述列表中的系统调用函数大多数是不可重入的,其原因是:
a) 使用了静态数据结构,
b) 调用了malloc 或free
c) 是标准I/O函数 ; 六。SIGCHLD信号 -------IGN(该信号的默认动作是忽略)
.该信号的产生:
)子进程终止;
)子进程接收到SIGSTOP信号停止时;
)子进程处在停止态,接收到SIGCONT后唤醒时;
综上所述:只要子进程的状态发生变化,会对父进程发出SIGCHLD信号,默认处理的动作是忽略。 .借助 SIGCHLD 子进程回收。
)wait()--------阻塞等待子进程结束;
)waitpid()--------设置不阻塞(第二个参数WNOHANG)。如果这样设置,要设置轮询,才能将子进程回收。
)信号捕捉---子进程回收; .注意:
)子进程继承了父进程的 信号处理动作和 信号屏蔽字(mask),但并没有继承父进程的 未决信号集(sigpending)。
)注册信号捕捉函数的位置,和与其他进程发出信号的配合(必须在捕捉信号发出之前完成注册)。
“参考代码” 七。信号传参:
.int sigqueue(pid_t pid, int sig, const union sigval value); 成功返回0; 失败-;
sigqueue 向指定进程发送信号的同时携带参数(即它的第三个参数);
"注意:携带的数据。如果携带的是 地址:需注意,不同进程之间虚拟地址空间各自独立,将当前进程地址传递给另一进程没有实际意义"
.捕捉信号传参
)用该函数捕捉信号传递的数据: int sigaction(int signum, const struct sigaction* act, struct sigaction* oldact);
)当注册信号捕捉函数,希望获得更多关于该信号的信息,不应使用 sa_handler, 而应使用 sa_sigaction。 但同时 sa_flags 必须指定SA_SIGINFO.
siginfo_t 是一个成员十分丰富的结构体,携带者该信号的各种相关信息。 八。中断系统调用
.慢速系统调用(造成当前系统永久阻塞的)
)如read, write, wait, pause, sigsuspend, 都是慢速系统调用 ;
)概念: 可能使进程永远阻塞的一类系统调用;如果再阻塞期间收到一个信号,该系统调用被中断,不再继续执行;也可以通过设置,使其中断后再重新启动。
)特点:慢速系统调用被中断的相关行为,实际上就是pause的行为: 如read()
) 信号不能被屏蔽, 执行默认动作, 忽略;
)信号的处理方式必须被捕捉;
)中断后返回-, 设置errno为 EINTR(表示:“被信号终端”); )设置sa_flags 参数来决定它终端后的行为:
表示被捕捉的信号,在捕捉函数执行期间被自动屏蔽
SA_NODEFER 表示被捕捉的信号,在捕捉函数执行期间不被自动屏蔽
SA_INTERRURT 表示慢速系统调用,若被信号打断,不再重启
SA_RESTART 表示慢速系统调用,若被信号打断,重启
SA_SIGINFO 表示捕捉函数是3参的sigaction,需指定为这个宏名 .其他系统调用:
如Lgetpid(), fork(); 十。终端
.字符终端(虚拟终端),图形终端(伪终端),网络终端(伪终端)。
.线路规程(line discipline):
像一个过滤器,对于某些特殊字符并不是让它直接通过,而是做特殊处理,比如ctrl+c,对应的字符并不会被用户程序read读到,而是被线路规程截获,
解释称SIGINT信号发送给前台进程,通常会使该进程停止。线路规程应该过滤哪些字符和做哪些特殊处理是可以配置的。
.在终端设备(如键盘)上输入内容进入进程的顺序:
终端设备--》终端设备驱动--》line discipline(线路规程过滤)---》系统调用(普通内容)---》用户进程
---》内核特殊字符(解释称信号)--》内核 前台进程。;
.一套伪终端由一个主设备(PTY Master)和一个从设备(PTY Slave)组成;主设备在概念上相当于键盘、显示器,只不过他不是一个真正的硬件而是一个内核模块;
操作它的也不是用户,而是另外一个内核模块。 网络终端或图形终端窗口的shell进程以及它启动的其他进程都认为自己的控制终端是伪终端从设备。 十一。进程组
pid_t getpgid(pid_t pid); 返回指定进程组的ID
pid_t getpgrp(void); 返回调用函数进程组的ID
int setpgid(pid_t pid, pid_t pgid); 设置某个进程的进程组ID; 成功返回0;失败-;
.当父进程创建子进程时,默认子进程与父进程属于同一进程组。其进程组ID==父进程的ID。
.进程组的生命周期: 只要进程组中有一个进程存在,该进程组就存在,"与组长进程是否终止无关"。
进程组创建到最后一个进程离开(终止或转移到另一个进程组)。
.一个进程可以为自己或子进程设置进程组ID。 .修改一个进程的进程组ID需注意:
1)如改变子进程为新的组,应在fork后,exec前。
)权限问题。非root用户只能改变自己和它创建的子进程的进程组。 十二。会话。
pid_t getsid(pid_t pid);获取该进程的会话ID(如果查看当前进程的会话ID,参数为0就行。自己测试吧)。成功:返回会话ID; 失败:返回-,并设置errno .
pid_t setpid(void); 创建一个会话,以自己的ID为新会话的ID,同时也会成为一个新的进程组。 成功:返回调用进程的ID;失败,-;
创建会话应注意:
.创建会话的进程不能是进程组组长;同时创建的进程变成新会话首进程(即组长)。
.创建完后该进程成为新进程组的组长进程。
.需要有root权限;(ubauntu不需要)
.新会话丢弃原有的控制终端,该会话没有控制终端(也就无法与用户进行交互)。
.该调用进程是组长进程,则出错返回。(与1 相同)。
.新建会话时,先调用fork,父进程退出;子进程创建会话(调用setsid()函数)。 "注意:子进程不会随着成为新的进程组组长,而其父进程发生改变。" 十三:守护进程:
.Daemon(精灵)进程,即守护进程。
特征: .位于Linux后台,服务进程。
.独立于控制终端(即没有控制终端),周期性的执行某任务,等待某事件
.不受用户的注销、登录而终止;(注意:不是关机)。
.通常采用以d结尾的名字。 .创建守护进程的模型:
.创建子进程,父进程退出
所有工作在子进程中进行,形式上脱离了控制终端。
.在子进程中创建新会话
setsid()函数
使子进程完全独立出来,脱离控制 .改变当前目录为根目录;
chdir()函数;
目的:防止占用可卸载的文件系统。
也可换成其他目录,只要该目录稳定,不会被卸载(当时卸载的优盘目录)。 .重设文件掩码;
umask()函数:
目的: 防止继承的文件创建屏蔽字拒绝某些权限;
增加守护进程的灵活性 .关闭文件描述符
继承的打开不会用到,浪费系统资源,无法卸载。 .执行守护进程核心工作 .设置守护进程退出。 "===信号========================================================================================================================"

Linux系统编程之----》信号的更多相关文章

  1. linux系统编程之信号(七)

    今天继续学习信号,主要是学习关于时间和定时器相关的函数的使用,关于这个实际上有很多内容,这里先简要进行说明,等之后再慢慢进行相关深入,也主要是为接下来要做的一个综合linux系统编程的例子做准备,好了 ...

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

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

  3. linux系统编程之信号(二)

    经过了漫长的间歇,对于c语言的学习也被中断了很久,现实确实有很多的无耐,计划中的事情总会被打乱,但不管怎样,学习的道路是不能休止的,所以经过了一断温习后现在继续学习C语言,话不多说,进入正题: 信号分 ...

  4. linux系统编程之信号(七):被信号中断的系统调用和库函数处理方式

        一些IO系统调用执行时, 如 read 等待输入期间, 如果收到一个信号,系统将中断read, 转而执行信号处理函数. 当信号处理返回后, 系统遇到了一个问题: 是重新开始这个系统调用, 还是 ...

  5. linux系统编程之信号(三):信号安装、signal、kill,arise讲解

    一,信号安装 如果进程要处理某一信号,那么就要在进程中安装该信号.安装信号主要用来确定信号值及进程针对该信号值的动作之间的映射关系,即进程将要处理哪个信号:该信号被传递给进程时,将执行何种操作. li ...

  6. linux系统编程之信号(二):信号处理流程(产生、注册、注销、执行)

        对于一个完整的信号生命周期(从信号发送到相应的处理函数执行完毕)来说,可以分为三个阶段: 信号诞生 信号在进程中注册 信号在进程中的注销 信号处理函数执行 1    信号诞生     信号事件 ...

  7. linux系统编程之信号(一)

    今天起,开始新的知识的学习,对于上个系列进程的学习还差一个理论上的总结,这个会下次补回来,以便通过实践之后,再用理论将其巩固一下,好了,话不多说,开始进入这个主题的学习----信号,很重要,但不是太容 ...

  8. linux系统编程之信号(八):三种时间结构及定时器setitimer()详解

    一,三种时间结构 time_t://seconds   struct timeval { long tv_sec; /* seconds */ long tv_usec; /* microsecond ...

  9. linux系统编程之信号(六):信号发送函数sigqueue和信号安装函数sigaction

    一,sigaction() #include <signal.h> int sigaction(int signum,const struct sigaction *act,struct ...

  10. linux系统编程之信号(五):信号集操作函数,信号阻塞与未决

    一,信号集及相关操作函数 信号集被定义为一种数据类型: typedef struct { unsigned long sig[_NSIG_WORDS]: } sigset_t 信号集用来描述信号的集合 ...

随机推荐

  1. Java中的服务器与客户端的简单连接

    Java中重点之一就是服务器与客户端的连接,因为是在同一台PC上,所以就设置服务器的地址为“localhost”,注意,我当时试着设置其他名称,但都不行,这个原因还请老司机告一下.另外还要注意,服务端 ...

  2. ES6 函数参数的默认值

    基本用法 在ES6之前,不能直接为函数的参数指定默认值,只能采取变通的方法. function log(x,y){ y = y||'world'; console.log(x,y); } log('k ...

  3. [转]ssm整合1(环境搭建)

    1 MyEclipse+Tomcat+MAVEN+SVN项目完整环境搭建http://blog.csdn.net/zhshulin/article/details/307798732 apache-m ...

  4. CentOS 6.9使用iptables搭建网关服务器(转)

    条件: 网关服务器IP:172.16.0.1,并且可以连接到外网 客户端IP:172.16.0.0/24 1.开启转发支持forward /etc/sysctl.conf net.ipv4.ip_fo ...

  5. Clover 的功能就是给资源管理器加上 Chrome 一样的标签页

    官网下载地址:http://cn.ejie.me/

  6. Java RSA加密算法生成公钥和私钥

    原文:http://jingyan.baidu.com/article/6dad5075f33466a123e36ecb.html?qq-pf-to=pcqq.c2c 目前为止,RSA是应用最多的公钥 ...

  7. TJSONTableObject跨平台解析JSON

    TJSONTableObject跨平台解析JSON USES SynCrossPlatformJSON TSQLRecordPeoplePersistent = class(TPersistent) ...

  8. python接口自动化21-规范的API接口文档示例

    前言 接口文档到底长啥样?做接口测试最大的障碍在于没有接口文档,很多公司不注重接口文档的编写,导致测试小伙伴没见过接口文档. 运气好一点的测试小伙伴可能厚着脸皮找开发要过接口文档,然而拿过来的接口文档 ...

  9. Eclipse中执行maven命令

    1.如下图,右击需要执行maven命令的工程,选择"Debug As"或"Run As",再选择"Maven build..." 进行如上操 ...

  10. linux下搭建SVN服务器完全手册

    原文:http://www.cnblogs.com/wrmfw/archive/2011/09/08/2170465.html 系统环境        RHEL5.4最小化安装(关iptables,关 ...