sigsuspend sigprocmask函数的用法

一个进程的信号屏蔽字规定了当前堵塞而不能递送给该进程的信号集调用函数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

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

转载于:https://www.cnblogs.com/gcczhongduan/p/4519008.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/459385.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MATLAB图像小波变换

为什么80%的码农都做不了架构师&#xff1f;>>> 小波变换与小波包变换 人脸图像f(x,y) 的一层小波变换如下图所示&#xff1a; 图中L 和H 分别表示低通滤波器和高通滤波器&#xff0c;l(n) 和h(n) 分别表示它们相应的脉冲响应&#xff0c;2↓1表示降2采样fLL和fHH分…

网络:TCP维护安全可靠机制提供的定时器

一、TCP为维护安全可靠机制提供了七大定时器 1、连接建立(connectionestablishment)”定时器&#xff1a; 在发送SYN报文段建立一条新连接时启动。如果在75秒内没有收到响应&#xff0c;连接建立将中止。 2、重传(retransmission)定时器&#xff1a; 在TCP发送某个数据段时设定…

grunt之Gruntfile(1)

grunt 执行的时候&#xff0c;他会找该目录下的Gruntfile文件&#xff0c;所以&#xff0c;要在目录下创建Gruntfile文件。 下面我demo一个copy任务&#xff1a; 执行copy&#xff0c;首先我们要一个copy的模块&#xff0c;那么我们先安装下copy模块 首先&#xff0c;我到H盘&a…

MyEclipse从数据库反向生成实体类之Hibernate方式 反向工程

2019独角兽企业重金招聘Python工程师标准>>> 开发项目涉及到的表太多&#xff0c;一个一个的写JAVA实体类很是费事。MyEclipse提供简便的方法&#xff1a;反向数据库 步骤大致如下: 第一步&#xff1a; window-->open Perspective-->MyEclipse Java Persisten…

TCP的定时器系列 — 超时重传定时器(有图有代码有真相!!!)

转载 主要内容&#xff1a;TCP定时器概述&#xff0c;超时重传定时器、ER延迟定时器、PTO定时器的实现。 内核版本&#xff1a;3.15.2 我的博客&#xff1a;http://blog.csdn.net/zhangskd Q&#xff1a;一条TCP连接会使用多少个定时器呢&#xff1f; A&#xff1a;目前的答案…

Python try/except/finally等

Python try/except/finally等 [代码块]x abc def fetcher(obj, index): return obj[index] fetcher(x, 4) 输出&#xff1a; File "test.py", line 6, in <module> fetcher(x, 4) File "test.py", line 4, in fetcher retur…

TCP的定时器系列 — SYNACK定时器

转载 主要内容&#xff1a;SYNACK定时器的实现&#xff0c;TCP_DEFER_ACCPET选项的实现。 内核版本&#xff1a;3.15.2 我的博客&#xff1a;http://blog.csdn.net/zhangskd 在上一篇博客中&#xff0c;已经连带介绍了SYNACK定时器的创建和删除&#xff0c;所以本文直接从它的…

android -- 蓝牙 bluetooth (二) 打开蓝牙

4.2的蓝牙打开流程这一部分还是有些变化的&#xff0c;从界面上看蓝牙开关就是设置settings里那个switch开关&#xff0c;widget开关当然也可以&#xff0c;起点不同而已&#xff0c;后续的流程是一样的。先来看systemServer.java的代码&#xff0c;蓝牙服务开启的地方&#xf…

开始nodejs+express的学习+实践(8)

为什么80%的码农都做不了架构师&#xff1f;>>> 1.session使用 介绍的非常详细&#xff1a; http://www.cnblogs.com/chenchenluo/p/4197181.html 对比我们的app.js需要引入express-session模块和使用这个模块&#xff0c;在package依赖&#xff0c;并加载。 我们修…

TCP的定时器系列 — 保活定时器(有图有代码有真相!!!)

转载 主要内容&#xff1a;保活定时器的实现&#xff0c;TCP_USER_TIMEOUT选项的实现。 内核版本&#xff1a;3.15.2 我的博客&#xff1a;http://blog.csdn.net/zhangskd 原理 HTTP有Keepalive功能&#xff0c;TCP也有Keepalive功能&#xff0c;虽然都叫Keepalive&#xff0c…

浅谈 Scala 中下划线的用途

Scala 作为一门函数式编程语言&#xff0c;对习惯了指令式编程语言的同学来说&#xff0c;会不大习惯&#xff0c;这里除了思维方式之外&#xff0c;还有语法层面的&#xff0c;比如 underscore&#xff08;下划线&#xff09;就会出现在多种场合&#xff0c;令初学者相当疑惑&…

maven项目部署到linux上的奇葩问题

2019独角兽企业重金招聘Python工程师标准>>> 经常会遇到这样子的问题&#xff0c;maven项目在本地的eclipse配置的好好的&#xff0c;结果一到服务器就运行不起来。 当然遇到这种情况&#xff0c;我们首先会想到环境变量和相关的路径问题&#xff0c;但是当这两个条…

TCP的定时器系列 — 零窗口探测定时器(有图有代码有真相!!!)

转载 主要内容&#xff1a;零窗口探测定时器的实现。 内核版本&#xff1a;3.15.2 我的博客&#xff1a;http://blog.csdn.net/zhangskd 出现以下情况时&#xff0c;TCP接收方的接收缓冲区将被塞满数据&#xff1a; 发送方的发送速度大于接收方的接收速度。 接收方的应用程序未…

java中XPATH操作xml,非常便捷

<?xml version"1.0" encoding"UTF-8"?> <MessageList><item type"1"><template_id value"p2ItJPj0taTTP4QRXP-z51nYuD3aDNhgvLOusWGY4p0"/><topcolor value"#173177"/><first value&quo…

【python】r+,w+ 全局变量

来源&#xff1a;http://www.educity.cn/wenda/352188.html r&#xff1a;可读可写&#xff0c;若文件不存在&#xff0c;报错w: 可读可写&#xff0c;若文件不存在&#xff0c;创建文本模式&#xff1a;遇换行符时根据操作系统不同自动转换换行符&#xff0c;比如读文件时遇\n…

网络:TCP通讯之 time_wait 状态

基于TCP协议的通讯流程1、TCP建立连接2、TCP断开连接3、TCP状态转换TCP状态解释&#xff1a; SYN-RECVD&#xff1a;再收到和发送一个连接请求后等待对方对连接请求的确认 ESTABLISHED&#xff1a;代表一个打开的连接 FIN-WAIT-1&#xff1a;等待远程TCP连接中断请求&#xff0…

linux下echo与time服务的程序实现

一、针对ECHO服务的TCP客户软件的实现 1.网络拓扑结构&#xff1a; 2.源码&#xff1a; 1 #include <stdio.h>2 #include <stdlib.h>3 #include <unistd.h>4 #include <string.h>5 #include <stdarg.h>6 #include <sys/types.h>7 #include…

iOS UI-AlertView(警示框)和ActionSheet(选择框、操作表单)

1 #import "ViewController.h"2 3 interface ViewController ()<UIAlertViewDelegate,UIActionSheetDelegate>4 5 end6 7 implementation ViewController8 9 #pragma mark - 生命周期10 - (void)viewDidLoad {11 [super viewDidLoad];12 // 创建展示Al…

Linux高性能服务器编程:进程池和线程池原理及应用(有图有代码有真相!!!)

一、问题引入 在前面编写多进程、多线程服务器时通过动态创建子进程和子线程来实现并发服务器&#xff0c;这样做有以下缺点&#xff1a; 1&#xff09;动态创建进程、线程将会比较耗费时间&#xff0c;将导致较慢的客户响应。 2&#xff09;动态创建的子进程只为一个客户服…

Linux:多进程、多线程服务器的实现解析(有图有代码有真相!!!)

一、问题引入 阻塞型的网络编程接口 几乎所有的程序员第一次接触到的网络编程都是从 listen()、send()、recv()等接口开始的。使用这些接口可以很方便的构建服务器 /客户机的模型。 我们假设希望建立一个简单的服务器程序&#xff0c;实现向单个客户机提供类似于“一问一答”的…