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

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

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. 信号集操作函数,信号未决、阻塞、递达

    转载:信号集操作函数,信号阻塞与未决 一,信号集及相关操作函数 信号集被定义为一种数据类型: typedef struct { unsigned long sig[_NSIG_WORDS]: } si ...

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

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

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

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

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

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

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

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

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

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

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

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

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

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

最新文章

  1. 跟我一起写 Makefile(十二)
  2. MTM:matlab实现5主函数解码
  3. R语言:ggplot2
  4. zuul默认的路由规则及禁用路由规则
  5. 简单帐表插件开发示例分享
  6. 距离高考出成绩,一年了、、、
  7. 天池在线编程 2020国庆八天乐 - 8. 分糖果
  8. 任正非:鸿蒙不用于手机;IBM 340 亿美元红帽收购案完成;Firefox 68.0 发布 | 极客头条...
  9. creator找不到编译器 qt_Qt与Web混合开发(一)--简单使用
  10. 【图像压缩】基于matlab GUI哈达玛变换图像压缩【含Matlab源码 845期】
  11. pk8/pem秘钥转keystore格式
  12. 如何用万用表检测电路
  13. 锂电池充电原理__2020.03.10
  14. 知识图谱从0到-1的笔记——6.知识推理
  15. 公司的苹果开发者账号续费问题
  16. Java面试知识点汇总
  17. 管理信息系统需求调研分析指南-软件工程-www.knowsky.com
  18. android11 root、android10 root、android9 root、android8.1 root、android6.0 root user版本权限开放
  19. 计算机网络-数据链路层 1
  20. python获取摄像头数据_用Python获取摄像头并实时控制人脸 !

热门文章

  1. python字典与yaml文件转换
  2. Pytorch使用Tensorboard记录loss曲线 (Tensorboard学习二)
  3. Python scipy拟合分布
  4. linux sort 排序 性能,Linux中sort 排序
  5. checkbox 选中_纯CSS修改checkbox复选框样式
  6. c语言 bcd码 16进制字符串 原理,ASCII码、HEX、字符、BCD 等等 基础知识思考
  7. jq 鼠标指向隐藏显示区域
  8. 列表的pop()和路径拼接问题
  9. 跟着alex学习了格式化输出,最大的感受就是编程这个事,一定要自己动手去做,才能学会。看会和自己会做完全是两码事...
  10. 使用Maven把项目打包成可执行jar在Idea里