一个进程的信号屏蔽字规定了当前堵塞而不能递送给该进程的信号集。调用函数sigprocmask能够检測或更改其信号屏蔽字,或者在一个步骤中同一时候运行这两个操作。

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

首先,若oset是非空指针,那么进程的当前信号屏蔽字通过oset返回。

其次,若set是一个非空指针,则參数how指示怎样改动当前信号屏蔽字。

表10-4说明了how可选用的值。注意,不能堵塞SIGKILL和SIGSTOP信号。

表10-4 用sigprocmask更改当前信号屏蔽字的方法

  how

  说明

  SIG_BLOCK   该进程新的信号屏蔽字是其当前信号屏蔽字和set指向信号集的并集。set包括了我们希望堵塞的附加信号
  SIG_UNBLOCK   该进程新的信号屏蔽字是其当前信号屏蔽字和set所指向信号集补集的交集。set包括了我希望解除堵塞的信号
  SIG_SETMASK   该进程新的信号屏蔽字将被set指向的信号集的值取代

假设set是空指针,则不改变该进程的信号屏蔽字,how的值也无意义。

在调用sigprocmask后假设有不论什么未决的、不再堵塞的信号,则在sigprocmask返回前,至少会将当中一个信号递送给该进程。

1、有时候不希望在接到信号时就马上停止当前运行,去处理信号,同一时候也不希望忽略该信号,而是延时一段时间去调用信号处理函数。这样的情况是通过堵塞信号实现的。

2、信号堵塞和忽略信号的差别。

堵塞的概念和忽略信号是不同的。操作系统在信号被进程解除堵塞之前不会讲信号传递出去,被堵塞的信号也不会影响进程的行为,信号仅仅是临时被阻止传递。当进程忽略一个信号时,信号会被传递出去但进程会将信号丢弃。

1)头文件:#include <signal.h>

2)一个保护临界区代码的错误实例:(sigprocmask()和pause()实现)

#include <unistd.h>

#include <signal.h>

#include <stdio.h>

void handler(intsig)   //信号处理函数的实现

{

printf("SIGINT sig");

}

int main()

{

sigset_tnew,old;

structsigaction act;

act.sa_handler = handler;  //信号处理函数handler

sigemptyset(&act.sa_mask);

act.sa_flags = 0;

sigaction(SIGINT, &act, 0); //准备捕捉SIGINT信号

sigemptyset(&new);

sigaddset(&new, SIGINT);

sigprocmask(SIG_BLOCK, &new,&old); //将SIGINT信号堵塞,同一时候保存当前信号集

printf("Blocked");

sigprocmask(SIG_SETMASK, &old,NULL);  //取消堵塞

pause();

return0;

}

上面实例的问题是:本来期望pause()之后,来SIGINT信号,能够结束程序;但是,假设当“取消堵塞”和“pause”之间,正好来了SIGINT信号,结果程序由于pause的原因会一直挂起。。。

解决的方式,当然是sigsuspend()函数了。

3)使用sigsuspend()的程序

#include <unistd.h>

#include <signal.h>

#include <stdio.h>

void handler(int sig)  //信号处理程序

{

if(sig == SIGINT)

printf("SIGINT sig");

else if(sig == SIGQUIT)

printf("SIGQUIT sig");

else

printf("SIGUSR1 sig");

}

int main()

{

sigset_tnew,old,wait;   //三个信号集

structsigaction act;

act.sa_handler = handler;

sigemptyset(&act.sa_mask);

act.sa_flags = 0;

sigaction(SIGINT, &act,0);   //能够捕捉下面三个信号:SIGINT/SIGQUIT/SIGUSR1

sigaction(SIGQUIT, &act, 0);

sigaction(SIGUSR1, &act, 0);

sigemptyset(&new);

sigaddset(&new,SIGINT);  //SIGINT信号增加到new信号集中

sigemptyset(&wait);

sigaddset(&wait, SIGUSR1); //SIGUSR1信号增加wait

sigprocmask(SIG_BLOCK, &new,&old);      //将SIGINT堵塞,保存当前信号集到old中

//临界区代码运行

if(sigsuspend(&wait) != -1) //程序在此处挂起;用wait信号集替换new信号集。即:过来SIGUSR1信 号,堵塞掉,程序继续挂起;过来其它信号,比如SIGINT,则会唤醒程序。运行sigsuspend的原子操作。注意:假设“sigaddset(&wait,SIGUSR1);”这句没有,则此处不会堵塞不论什么信号,即过来不论什么信号均会唤醒程序。

printf("sigsuspend error");

printf("Aftersigsuspend");

sigprocmask(SIG_SETMASK, &old, NULL);

return0;

}

sigsuspend的原子操作是:

(1)设置新的mask堵塞当前进程(上面是用wait替换new,即堵塞SIGUSR1信号)

(2)收到SIGUSR1信号,堵塞,程序继续挂起;收到其它信号,恢复原先的mask(即包括SIGINT信号的)。

(3)调用该进程设置的信号处理函数(程序中假设先来SIGUSR1信号,然后过来SIGINT信号,则信号处理函数会调用两次,打印不同的内容。第一次打印SIGINT,第二次打印SIGUSR1,由于SIGUSR1是前面堵塞的)

(4)待信号处理函数返回,sigsuspend返回了。(sigsuspend将捕捉信号和信号处理函数集成到一起了)

总结:

在nginx源代码中,ngx_master_process_cycle函数中,首先调用了sigprocmask()函数堵塞了部分信号,在for循环中调用了sigsuspend函数 ,可是sigsuspend函数中的set为空,也就是说,在for循环之前,假设有set集合中的信号到来就堵塞,在for循环之内,不论什么信号到来都进程处理。函数返回之后同一时候也恢复了原来的信号掩码!

sigsuspend的整个原子操作过程为:

(1) 设置新的mask堵塞当前进程;

(2) 收到信号,恢复原先mask;

(3) 调用该进程设置的信号处理函数;

(4) 待信号处理函数返回后,sigsuspend返回。

大致就是上面这个过程,噢,原来signal handler是原子操作的一部分,并且是在恢复屏蔽字后运行的,

int sigsuspend(const sigset_t *sigmask);

此函数用于进程的挂起,sigmask指向一个信号集。当此函数被调用时,sigmask所指向的信号集中的信号将赋值给信号掩码。之后进程挂起。直到进程捕捉到信号,并调用处理函数返回时,函数sigsuspend返回。信号掩码恢复为信号调用前的值,同一时候将errno设为EINTR。进程结束信号可将其马上停止。

    #include <stdio.h>
#include <signal.h> void checkset();
void func();
void main()
{
sigset_tblockset,oldblockset,zeroset,pendmask;
printf("pid:%ld\n",(long)getpid());
signal(SIGINT,func); sigemptyset(&blockset);
sigemptyset(&zeroset);
sigaddset(&blockset,SIGINT); sigprocmask(SIG_SETMASK,&blockset,&oldblockset);
checkset();
sigpending(&pendmask); if(sigismember(&pendmask,SIGINT))
printf("SIGINTpending\n");
//不堵塞不论什么信号 不论什么信号到来都会激活进程
if(sigsuspend(&zeroset)!= -1)
{
printf("sigsuspenderror\n");
exit(0);
} printf("afterreturn\n");
sigprocmask(SIG_SETMASK,&oldblockset,NULL); printf("SIGINTunblocked\n");
} void checkset()
{ sigset_tset;
printf("checksetstart:\n");
if(sigprocmask(0,NULL,&set)<0)
{
printf("checksetsigprocmask error!!\n");
exit(0);
} if(sigismember(&set,SIGINT))
printf("sigint\n"); if(sigismember(&set,SIGTSTP))
printf("sigtstp\n"); if(sigismember(&set,SIGTERM))
printf("sigterm\n");
printf("checksetend\n");
} void func()
{
printf("hellofunc\n");
}

结果:

pid:5474
checksetstart:
sigint
checksetend
^Chellofunc
afterreturn
checksetstart:
checksetend
SIGINTunblocked

从执行的结果 以及和上面的样例进行比較较就能够知道这两个函数的函数。

sigsuspend sigprocmask函数的用法的更多相关文章

  1. 有关日期的函数操作用法总结,to_date(),trunc(),add_months();

    相关知识链接: Oracle trunc()函数的用法 oracle add_months函数 Oracle日期格式转换,tochar(),todate() №2:取得当前日期是一个星期中的第几天,注 ...

  2. Oracle to_date()函数的用法

    Oracle to_date()函数的用法 to_date()是Oracle数据库函数的代表函数之一,下文对Oracle to_date()函数的几种用法作了详细的介绍说明,供您参考学习. 在Orac ...

  3. js中bind、call、apply函数的用法

    最近一直在用 js 写游戏服务器,我也接触 js 时间不长,大学的时候用 js 做过一个 H3C 的 web的项目,然后在腾讯实习的时候用 js 写过一些奇怪的程序,自己也用 js 写过几个的网站.但 ...

  4. Oracle trunc()函数的用法

    Oracle trunc()函数的用法 /**************日期********************/1.select trunc(sysdate) from dual --2013-0 ...

  5. freemarker内置函数和用法

    原文链接:http://www.iteye.com/topic/908500 在我们应用Freemarker 过程中,经常会操作例如字符串,数字,集合等,却不清楚Freemrker 有没有类似于Jav ...

  6. matlab中patch函数的用法

    http://blog.sina.com.cn/s/blog_707b64550100z1nz.html matlab中patch函数的用法——emily (2011-11-18 17:20:33) ...

  7. JavaScript中常见的数组操作函数及用法

    JavaScript中常见的数组操作函数及用法 昨天写了个帖子,汇总了下常见的JavaScript中的字符串操作函数及用法.今天正好有时间,也去把JavaScript中常见的数组操作函数及用法总结一下 ...

  8. JavaScript中常见的字符串操作函数及用法

    JavaScript中常见的字符串操作函数及用法 最近几次参加前端实习生招聘的笔试,发现很多笔试题都会考到字符串的处理,比方说去哪儿网笔试题.淘宝的笔试题等.如果你经常参加笔试或者也是一个过来人,相信 ...

  9. oracle的substr函数的用法

    oracle的substr函数的用法 取得字符串中指定起始位置和长度的字符串   substr( string, start_position, [ length ] ) 如:     substr( ...

随机推荐

  1. 使用vue-cil搭建项目

    原文: 简书原文:https://www.jianshu.com/p/1af9b72cf86e 大纲 1.安装NodeJs 2.安装vue-cli 3.创建项目 4.启动项目 5.打包项目 6.项目实 ...

  2. <p><span style="font-size:14px">近期须要批量将PNM&#26684;式的文件转换成GIF文件。我尝试了例如以下的图像转换工具:</span></p>

    近期须要批量将PNM格式的文件转换成GIF文件.我尝试了例如以下的图像转换工具: ImageBatch:全然免费,但只支持PNG JPEG BMP GIF四种格式 OfficeConverter:在线 ...

  3. php框架排名(Laravel一直第一)

    php框架排名(Laravel一直第一) 一.总结 1.Laravel,后面就用这个框架(要用好这个框架,英语得6啊) 2.YII框架和tp框架一样,也是一个国产框架 二.2017世界PHP框架排名T ...

  4. 【计算机】基本概念的理解 —— 沙盒(sandbox)、交互式计算/编程/应用

    web scraper:网络铲: scraper:n. 刮刀:铲土机:守财奴: 1. 交互式计算/编程/应用(interactive computing/application/programming ...

  5. (十四)RabbitMQ消息队列-启用SSL安全通讯

    原文:(十四)RabbitMQ消息队列-启用SSL安全通讯 如果RabbitMQ服务在内网中,只有内网的应用连接,我们认为这些连接都是安全的,但是个别情况我们需要让RabbitMQ对外提供服务.这种情 ...

  6. Spring常用工具类(ApplicationContextAware、DisposableBean、InitializingBean)

    原创作品,出自 "晓风残月xj" 博客,欢迎转载,转载时请务必注明出处(http://blog.csdn.net/xiaofengcanyuexj). 由于各种原因,可能存在诸多不 ...

  7. 最简单的基于FFmpeg的移动端样例:IOS HelloWorld

    ===================================================== 最简单的基于FFmpeg的移动端样例系列文章列表: 最简单的基于FFmpeg的移动端样例:A ...

  8. 【Nutch2.2.1基础教程之1】nutch相关异常 分类: H3_NUTCH 2014-08-08 21:46 1549人阅读 评论(2) 收藏

    1.在任务一开始运行,注入Url时即出现以下错误. InjectorJob: Injecting urlDir: urls InjectorJob: Using class org.apache.go ...

  9. css3 border img 边框图片

    摘自http://www.html-js.com/article/CSS3-tutorial-css3borderimage-frame-image-Xiangjie-on border-image摘 ...

  10. Shuttle ESB(三)——架构模型介绍(2)

    上一篇文章中,介绍了Shuttle ESB架构模型中的三个重要部分. 今天,我们继续介绍剩余的三个内容:模式和消息路由. 四.模式 Request/Response(请求/响应模式) 对基于Reque ...