转载:信号集操作函数,信号阻塞与未决

一,信号集及相关操作函数

信号集被定义为一种数据类型:

typedef struct {

unsigned long sig[_NSIG_WORDS];

} sigset_t

信号集用来描述信号的集合,每个信号占用一位(64位)。Linux所支持的所有信号可以全部或部分的出现在信号集中,主要与信号阻塞相关函数配合使用。下面是为信号集操作定义的相关函数:

#include <signal.h>

int sigemptyset(sigset_t *set);

int sigfillset(sigset_t *set);

int sigaddset(sigset_t *set, int signum)

int sigdelset(sigset_t *set, int signum);

int sigismember(const sigset_t *set, int signum);

sigemptyset(sigset_t *set)初始化由set指定的信号集,信号集里面的所有信号被清空,相当于64为置0;

sigfillset(sigset_t *set)调用该函数后,set指向的信号集中将包含linux支持的64种信号,相当于64为都置1;

sigaddset(sigset_t *set, int signum)在set指向的信号集中加入signum信号,相当于将给定信号所对应的位置1;

sigdelset(sigset_t *set, int signum)在set指向的信号集中删除signum信号,相当于将给定信号所对应的位置0;

sigismember(const sigset_t *set, int signum)判定信号signum是否在set指向的信号集中,相当于检查给定信号所对应的位是0还是1。

示例程序:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
void print_sigset(sigset_t *set);
int main(void)
{sigset_t myset;sigemptyset(&myset);sigaddset(&myset,SIGINT);sigaddset(&myset,SIGQUIT);sigaddset(&myset,SIGUSR1);sigaddset(&myset,SIGRTMIN);print_sigset(&myset);return 0;}
void print_sigset(sigset_t *set)
{int i;for(i = 1; i < NSIG; ++i){if(sigismember(set,i))printf("1");elseprintf("0");}putchar('\n');
}

结果:

可以看到添加信号的相应位置1.

二,信号阻塞与未决

man帮助说明:

Signal mask and pending signals
       A signal may be blocked, which means that it will not be delivereduntil it is later unblocked.  Between the time when it is generatedand when it is delivered a signal is said to be pending.       Each thread in a process has an independent signal mask, whichindicates the set of signals that the thread is currently blocking.A thread can manipulate its signal mask using pthread_sigmask(3).  Ina traditional single-threaded application, sigprocmask(2) can be usedto manipulate the signal mask.
执行信号的处理动作称为信号递达(Delivery),信号从产生到递达之间的状态,称为信号未决(Pending)。进程可以选择阻塞(Block)某个信号。被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。每个进程都有一个用来描述哪些信号递送到进程时将被阻塞的信号集,该信号集中的所有信号在递送到进程后都将被阻塞。
信号在内核中的表示可以看作是这样的:
看图说话:
block集(阻塞集、屏蔽集):一个进程所要屏蔽的信号,在对应要屏蔽的信号位置1
pending集(未决信号集):如果某个信号在进程的阻塞集中,则也在未决集中对应位置1,表示该信号不能被递达,不会被处理
handler(信号处理函数集):表示每个信号所对应的信号处理函数,当信号不在未决集中时,将被调用
 
以下是与信号阻塞及未决相关的函数操作:

#include <signal.h>

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

int sigpending(sigset_t *set));

int sigsuspend(const sigset_t *mask));

sigprocmask()函数能够根据参数how来实现对信号集的操作,操作主要有三种:

  • SIG_BLOCK 在进程当前阻塞信号集中添加set指向信号集中的信号,相当于:mask=mask|set
  • SIG_UNBLOCK 如果进程阻塞信号集中包含set指向信号集中的信号,则解除对该信号的阻塞,相当于:mask=mask|~set
  • SIG_SETMASK 更新进程阻塞信号集为set指向的信号集,相当于mask=set

sigpending(sigset_t *set))获得当前已递送到进程,却被阻塞的所有信号,在set指向的信号集中返回结果。

sigsuspend(const sigset_t *mask))用于在接收到某个信号之前, 临时用mask替换进程的信号掩码, 并暂停进程执行,直到收到信号为止。

sigsuspend 返回后将恢复调用之前的信号掩码。信号处理函数完成后,进程将继续执行。该系统调用始终返回-1,并将errno设置为EINTR。

示例程序:

#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>#define ERR_EXIT(m) \do \{ \perror(m); \exit(EXIT_FAILURE); \} while(0)void handler(int sig);
void printsigset(sigset_t *set)
{int i;for (i=1; i<NSIG; ++i){if (sigismember(set, i))putchar('1');elseputchar('0');}printf("\n");
}int main(int argc, char *argv[])
{sigset_t pset;sigset_t bset;sigemptyset(&bset);sigaddset(&bset, SIGINT);if (signal(SIGINT, handler) == SIG_ERR)ERR_EXIT("signal error");if (signal(SIGQUIT, handler) == SIG_ERR)ERR_EXIT("signal error");sigprocmask(SIG_BLOCK, &bset, NULL);//将信号加入进程阻塞集中for (;;){sigpending(&pset);printsigset(&pset);sleep(1);}return 0;
}void handler(int sig)
{if (sig == SIGINT)printf("recv a sig=%d\n", sig);else if (sig == SIGQUIT){sigset_t uset;sigemptyset(&uset);sigaddset(&uset, SIGINT);sigprocmask(SIG_UNBLOCK, &uset, NULL);}
}

结果:

说明:程序首先将SIGINT信号加入进程阻塞集(屏蔽集)中,一开始并没有发送SIGINT信号,所以进程未决集中没有处于未决态的信号,当我们连续按下ctrl+c时,向进程发送SIGINT信号,由于SIGINT信号处于进程的阻塞集中,所以发送的SIGINT信号不能递达,也是就是处于未决状态,所以当我打印未决集合时发现SIGINT所对应的位为1,现在我们按下ctrl+\,发送SIGQUIT信号,由于此信号并没被进程阻塞,所以SIGQUIT信号直接递达,执行对应的处理函数,在该处理函数中解除进程对SIGINT信号的阻塞,所以之前发送的SIGINT信号递达了,执行对应的处理函数,但由于SIGINT信号是不可靠信号,不支持排队,所以最终只有一个信号递达。

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <string.h>
#include <unistd.h>/* 版本1, 可靠信号将被递送多次 */
#define MYSIGNAL SIGRTMIN+5
/* 版本2, 不可靠信号只被递送一次 */
//#define MYSIGNAL SIGTERMvoid sig_handler(int signum)
{psignal(signum, "catch a signal");
}int main(int argc, char **argv)
{sigset_t block, pending;int sig, flag;/* 设置信号的handler */signal(MYSIGNAL, sig_handler);/* 屏蔽此信号 */sigemptyset(&block);sigaddset(&block, MYSIGNAL);printf("block signal\n");sigprocmask(SIG_BLOCK, &block, NULL);/* 发两次信号, 看信号将会被触发多少次 */printf("---> send a signal --->\n");kill(getpid(), MYSIGNAL);printf("---> send a signal --->\n");kill(getpid(), MYSIGNAL);/* 检查当前的未决信号 */flag = 0;sigpending(&pending);for (sig = 1; sig < NSIG; sig++) {if (sigismember(&pending, sig)) {flag = 1;psignal(sig, "this signal is pending");} }if (flag == 0) {printf("no pending signal\n");}/* 解除此信号的屏蔽, 未决信号将被递送 */printf("unblock signal\n");sigprocmask(SIG_UNBLOCK, &block, NULL);/* 再次检查未决信号 */flag = 0;sigpending(&pending);for (sig = 1; sig < NSIG; sig++) {if (sigismember(&pending, sig)) {flag = 1;psignal(sig, "a pending signal");} }if (flag == 0) {printf("no pending signal\n");}return 0;
}

结果:

两次执行结果不同:第一次连续发送两次不可靠信号,最后解除阻塞时,只有一个递达,说明不可靠信号不支持排队。

第二次执行时,连续两次发送可靠信号,解除阻塞后,都递达,说明可靠信号支持排队。

ok,这节就写到这吧

信号集操作函数,信号未决、阻塞、递达相关推荐

  1. Day53 Linux setitimer函数 信号集操作函数 信号捕捉 SIGCHLD信号

    目录 setitimer函数 信号集操作函数 1.信号集设定 2.igprocmask函数 3.sigpending函数 信号捕捉 1.signal函数 2.sigaction函数 SIGCHLD信号 ...

  2. Linux系统编程32:进程信号之详解信号集操作函数(sigset_t ,sigpending,sigprocmask)

    文章目录 (1)sigset_t (2)信号集操作函数 (1)sigset_t 前面说过,未决和阻塞分别用位图来表示,于是我们把保存位图这样的数据类型称为sigset_t,sigset_t称为信号集, ...

  3. linux中signal函数返回值,signal函数、sigaction函数及信号集操作函数

    信号是与一定的进程相联系的.也就是说一个进程可以决定在进程中对哪些信号进行什 么样的处理.例如一个进程可以忽略某些信号而只处理其他一些信号另外一个进程还可以选择如何处理信号.总之这些总与特定的进程相联 ...

  4. 对信号集操作函数的使用方法和顺序

    对信号集操作函数的使用方法和顺序如下: ①      使用signal或sigaction函数安装和登记信号的处理. ②      使用sigemptyset等定义信号集函数完成对信号集的定义. ③  ...

  5. linux的基础知识——signal信号捕捉,信号集操作函数

    文章目录 1.signal捕捉信号 2.信号集操作函数 3.sigprocmask函数 4.sigpending函数 5.例子1:打印某个进程未决信号集 6.例子2:signal函数的注册捕捉执行函数 ...

  6. 信号集操作函数,信号阻塞与未决

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

  7. _Linux系统编程—信号集操作函数

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

  8. 【B站视频笔记】linux 进程间通信(ipc)信号(软中断信号)signal库函数、可靠信号和不可靠信号、信号集sigprocmask(信号掩码、信号递达Delivery、信号未决Pending)

    [视频教程]Linux信号详解(可靠信号.不可靠信号.阻塞信号.信号处理函数) [博文]Linux信号 文章目录 背景 课程笔记 一.如何让程序在后台运行 1.加"&"符号 ...

  9. linux 与信号集操作相关的函数

    与信号集操作相关的函数 #include <signal.h> 清空信号集 全都为0 int sigemptyset(sigset_t *set);填充信号集 全都为1 int sigfi ...

最新文章

  1. HTML+CSS+JavaScript复习笔记持更(八)——CSS3常用属性之列表
  2. OpenCV bgfg分割的实例(附完整代码)
  3. java高并发(二)并发与高并发基本概念
  4. It's all about buffers: zero-copy, mmap and Java NIO
  5. else 策略模式去掉if_业务复杂=if else?刚来的大神竟然用策略+工厂彻底干掉了他们!...
  6. zookeeper一键启动关闭JAVA_HOME在PATH中找不到报错踩坑记
  7. jinja Whitespace Control
  8. codeforces C. Sonya and Problem Wihtout a Legend(dp or 思维)
  9. 程序相关概念及OS Linux发行版
  10. ITIL学习笔记——核心流程之:配置管理
  11. 安卓系统中默认打开蓝牙 HCI snoop 文件的方法
  12. Linux下sqlite3移植与编程
  13. [UE5 C++] 免费安装JetBrains Mono字体至IDE
  14. ZOJ3380_Patchouli's Spell Cards_概率DP
  15. 应用动态规划思想解决实际问题
  16. pscp linux,windows下 pscp 安装及使用
  17. 机器学习之朴素贝叶斯算法原理+Python实现
  18. 迅雷All in区块链
  19. 戴尔DELL灵越3881台式计算机,戴尔灵越3881台式机装win7系统及bios设置教程(支持10代cpu usb)...
  20. 内蒙古电网计算机专业分数线,华北电力大学智能电网信息工程专业2015年在内蒙古理科高考录取最低分数线...

热门文章

  1. FreeSql (二十八)事务
  2. Jmeter逻辑控制器-ForEach Controller
  3. xmind-HTTP协议
  4. leetcode练习——数组篇(1)(std::ios::sync_with_stdio(false);std::cin.tie(nullptr);)
  5. 《netty实战》阅读笔记(2)——Netty 的数据容器ByteBuf
  6. Oracle执行计划解释
  7. JavaScript 判断变量是否为数组Array的方法
  8. 只用2000行代码实现google protocol buffer c++版的功能
  9. SQL Server :理解数据记录结构
  10. 17 redis -key设计原则