信号源为目标进程产生了一个信号,然后由内核来决定是否要将该信号传递给目标进程。从信号产生到传递给目标进程的流程图如下图所示:

进程可以阻塞信号的传递。当信号源为目标进程产生了一个信号之后,内核会执行依次执行下面操作,

1. 如果目标进程设置了忽略该信号,则内核直接将该信号丢弃。

2. 如果目标进程没有阻塞该信号,则内核将该信号传递给目标进程,由目标进程执行相对应操作。

3. 如果目标进程设置阻塞该信号,则内核将该信号放到目标进程的阻塞信号列表中,等待目标进程对该类型信号的下一步设置。若目标进程后续设置忽略该信号,则内核将该信号从目标进程的阻塞信号列表中移除并丢弃。若目标进程对该信号解除了阻塞,内核将该信号传递给目标进程进行相对应的操作。

在信号产生到信号传递给目标进程之间的时间间隔内,我们称该信号为未决的(pending)。

每个进程都有一个信号屏蔽字(signal mask),它规定了当前要阻塞传递给该进程的信号集。对于每种可能的信号,信号屏蔽字中都有一位与之对应。

信号集:

函数 sigemptyset 初始化由 set 指向的信号集,清除其中所有信号。

1 int sigemptyset(sigset_t *set);

返回值:若成功则返回0,若出错则返回-1函数 sigfillset 初始化由 set 指向的信号集,使其包含所有信号。

2 int sigfillset(sigset_t *set);
返回值:若成功则返回0,若出错则返回-1

函数 sigaddset 将一个信号 signo 添加到现有信号集 set 中。

3 int sigaddset(sigset_t *set, int signo);
返回值:若成功则返回0,若出错则返回-1

函数 sigdelset 将一个信号 signo 从信号集 set 中删除。

4 int sigdelset(sigset_t *set, int signo);
返回值:若成功则返回0,若出错则返回-1

函数 sigismember 判断指定信号 signo 是否在信号集 set 中。

5 int sigismember(const sigset_t *set, int signo);
返回值:若真则返回1,若假则返回0,若出错则返回-1

函数sigprocmask

调用 sigprocmask 函数可以检测或者设置进程的信号屏蔽字。

#include <signal.h>
int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);
返回值:若成功则返回0,若出错则返回-1

若 oset 参数是一个非空指针,则进程的当前信号屏蔽字将通过 oset 返回。若 set 参数是一个非空指针,则参数 how 将指示如何修改当前信号屏蔽字。how 的可选值如下表所示:

how

说明

SIG_BLOCK

该进程新的信号屏蔽字是其当前信号屏蔽字和 set 指向信号集的并集。

SIG_UNBLOCK

该进程的信号屏蔽字是当前信号屏蔽字和 set 所指向信号集补给的交集。set 包含了我们希望解除阻塞的信号。

SIG_SETMASK

该进程新的信号屏蔽字设置为 set 所指向的信号集。

下面来看个具体的使用例子

void sig_alarm(int signo){

printf("received SIGALRM\n");

return;

}

void signal_set_fun(){

sigset_t sigset;

sigemptyset(&sigset);

sigaddset(&sigset,SIGALRM);

if(sigprocmask(SIG_BLOCK,&sigset,NULL)<0){

printf("sigprocmask error:\n");

}

if(signal(SIGALRM,sig_alarm) < 0){

printf("signal error:\n");

}

alarm(2);

sleep(4);

printf("before unblock sigprocmask\n");

if(sigprocmask(SIG_UNBLOCK,&sigset,NULL)<0){

printf("sigprocmask unblock error:\n");

}

}

在上面的程序文件中先调用 sigprocmask 设置阻塞信号 SIGALRM,然后调用 alarm(2) 设置一个两秒钟的闹钟(两秒钟之后将向当前进程产生一个 SIGALRM 信号)。在睡眠 4 秒钟之后(此时应该已经产生了 SIGALRM 信号),调用 sigprocmask 函数解除对信号SIGALRM 的阻塞。

运行结果如下:

函数sigpending

函数 sigpending 获取当前进程所有未决的信号。通过其 set 参数返回未决的信号集。

#include <signal.h>
int sigpending(sigset_t *set);
返回值:若成功则返回0,若出错则返回-1

来看一个实际使用的例子:

void alarm_is_pending(char *str){

sigset_t pendingsig;

printf("%s:\n",str);

if(sigpending(&pendingsig) < 0){

printf("sigpending required error:\n");

}

if(sigismember(&pendingsig,SIGALRM)){

printf("SIGALRM is pending\n");

}

else{

printf("SIGALRM is not pending\n");

}

}

void signal_pending_fun(){

sigset_t sigset;

sigemptyset(&sigset);

sigaddset(&sigset,SIGALRM);

if(sigprocmask(SIG_BLOCK,&sigset,NULL) < 0){

printf("sigprocmask error:\n");

}

alarm_is_pending("before alarm");

alarm(2);

sleep(4);

alarm_is_pending("after alarm");

exit(0);

}

运行结果:

linux c编程:信号(三) sigprocmask和sigpending函数的更多相关文章

  1. linux系统编程--信号

    信号的概念 man 7 siganl  查看man手册 信号在我们的生活中随处可见, 如:古代战争中摔杯为号:现代战争中的信号弹:体育比赛中使用的信号枪......他们都有共性:1. 简单 2. 不能 ...

  2. Linux系统编程——信号

    目录 信号的介绍 信号的机制 信号的编号 Linux常规信号一览表 信号的产生 终端按键产生信号 硬件异常产生信号 kill函数/命令产生信号 信号的操作函数 信号集设定 sigprocmask函数 ...

  3. linux进程编程:子进程创建及执行函数简介

    linux进程编程:子进程创建及执行函数简介 子进程创建及执行函数有三个: (1)fork();(2)exec();(3)system();    下面分别做详细介绍.(1)fork()    函数定 ...

  4. Linux系统编程—信号集操作函数

    先来回顾一下未决信号集是怎么回事. 信号从产生到抵达目的地,叫作信号递达.而信号从产生到递达的中间状态,叫作信号的未决状态.产生未决状态的原因有可能是信号受到阻塞了,也就是信号屏蔽字(或称阻塞信号集, ...

  5. Linux系统编程—信号捕捉

    前面我们学习了信号产生的几种方式,而对于信号的处理有如下几种方式: 默认处理方式: 忽略: 捕捉. 信号的捕捉,说白了就是抓到一个信号后,执行我们指定的函数,或者执行我们指定的动作.下面详细介绍两个信 ...

  6. UNIX环境高级编程——信号基本概述和signal函数

    一.为了理解信号,先从我们最熟悉的场景说起:1. 用户输入命令,在Shell下启动一个前台进程.2. 用户按下Ctrl-C,这个键盘输入产生一个硬件中断.3. 如果CPU当前正在执行这个进程的代码,则 ...

  7. Linux多任务编程之五:exit()和_exit()函数(转)

    来源:CSDN  作者:王文松   转自:Linux公社 ----------------------------------------------------------------------- ...

  8. Linux音频编程(三)混音器介绍

    一.介绍 1.mixer:用来控制多个输入.输出的音量,也控制输入(microphone,line-in,CD)之间的切换,可以将多个信号组合或者叠加在一起.声卡上的混音器由多个混音通道组成,它们可以 ...

  9. linux网络编程:三次握手与四次挥手

    建立TCP需要三次握手才能建立,而断开连接则需要四次握手.整个过程如下图所示: 其中三次握手即建立连接 四次挥手则为关闭连接 TCP连接的11种状态 客户端独有的:(1)SYN_SENT (2)FIN ...

随机推荐

  1. S1:适配器 Adapter

    将一个类的接口转换为用户期望的另外一个接口.适配器使得原本由于接口不兼容而不能一起工作的类可以一起工作   UML: 一.类适配器: class A { public function methodA ...

  2. 怎样取消Macbook上顽固的开机启动项

    博主遇到的一个顽固启动项是Cisco Anyconnect.我仅仅是偶尔须要使用VPN.可是安装了Cisco Anyconnect之后,每次开机它都会启动,非常烦人. 1 通过系统设置 首先,博主希望 ...

  3. STL学习笔记(第五章 STL组件)

    STL组件 若干精心勾画的组件共同合作,构筑起STL的基础.这些组件最关键的是容器.迭代器和算法. 下图演示了STL组件之间的合作 容器(Containers) 容器类别(简称容器)用来管理一组元素. ...

  4. ASP.NET综合管理ERP系统100%源代码+所有开发文档

    该系统开发环境为:VS2010,数据库採用SQL Server,框架为ASP.NET. 源代码包含所有文档说明,代码简单易懂,凝视完整. 提示:假设没有安装水晶报表系统执行会报错,报表安装程序已经打包 ...

  5. maven nexus myeclipse 学习

    http://b-l-east.iteye.com/blog/1246482 这篇文章比较详细的介绍了 nexus 本地仓库以及与maven的配合使用 http://blog.csdn.net/arv ...

  6. NSTimer注意内存泄露(真该死)

    NSTimer可以用来执行一些定时任务,比较常用的方法就是: + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTar ...

  7. delphi的字节对齐

    如果不改编译选项Delphi的Record默认也是4字节对齐的. 可以用编译开关指定 {$A4+}就是4字节对齐.同理{$A2+}.{$A1+}等.{$A1+}等同于Packed Record 主要容 ...

  8. asp.net core mvc视频A:笔记3-1.视图基本用法

    常用介绍 注意:ViewBag是对View的封装,所以如果两者键值(Key)是一样的话,后者会覆盖前者. 新建项目,添加空控制器 小技巧-快速添加视图 控制器方法,使用ViewData和ViewBag ...

  9. DOM概念的区分:Attribute和Property, html()及.text(), .val()

    Attribute就是dom节点自带的属性 例如:html中常用的id.class.title.align等: <div id="immooc" title="慕课 ...

  10. Guice 学习(七)常量和属性的注入( Constant and Property Inject)

    1.常量注入方式 package com.guice.ConstantInjectDemo; import com.google.inject.Binder; import com.google.in ...