信号驱动任务指的是通过信号来驱动任务的执行,每发送一次信号,任务就执行一次。实现该目的所需的函数就是 pause 或者 sigsuspend,pause和sigsuspend函数可以暂停当前进程,直至收到信号才会继续运行之后的程序。


目录

1、认识 pause / sigsuspend 函数

(1) pause 函数

(2) sigsuspend 函数

2、信号驱动任务执行的两种方式

(1) sigprocmask + pause

(2) sigsuspend


1、认识 pause / sigsuspend 函数

(1) pause 函数

pause 函数的作用是暂停当前进程(进入休眠状态),直至收到信号(任意信号),才会唤醒当前进程。

因为信号的处理动作有终止、忽略、捕捉、屏蔽,所以也对应了下面四种情况:

  • 信号的默认处理动作是终止,进程直接终止。
  • 信号的默认处理动作是忽略,进程继续处于挂起状态。
  • 信号的默认处理动作是捕捉,进程先调用信号处理函数,然后解除挂起,执行下一步。
  • 信号的默认处理动作是屏蔽,进程继续处于挂起状态。

(2) sigsuspend 函数

sigsuspend函数的作用也是暂停当前进程直至收到信号,但 sigsuspend 还可以主动设置屏蔽哪些信号,收到这些被屏蔽的信号时,不会解除挂起。

参数 mask:需要屏蔽的信号集。当前进程的屏蔽字会被替换为当前参数的屏蔽信号集,等到函数返回,会还原当前进程的屏蔽字。

  • mask == NULL:sigsuspend达到的效果和pause一样
  • mask != NULL:通过设置屏蔽信号集来主动屏蔽某些信号,收到这些被屏蔽的信号时,不会解除挂起

返回值:只会返回 -1。

2、信号驱动任务执行的两种方式

下面就以 2号信号为例,实现信号驱动任务执行。2号信号 SIGINT 可以终止前台进程,我们需要捕获2号信号,并设置相应的信号处理函数来避免当前进程被终止。

(1) sigprocmask + pause

执行任务的时候,我们不希望任务执行到一半被打断,所以在执行任务的之前我们需要调用 sigprocmask函数来屏蔽未来会收到的信号(当前场景下指的就是2号)

#include <stdio.h>
#include <signal.h>
#include <unistd.h>void handler(int signum)
{printf("收到并处理%d号信号\n", signum);
}int main(){signal(2, handler);    // 捕捉2号信号sigset_t set;sigemptyset(&set);      // 清空信号集sigaddset(&set, 2);    // 向信号集中添加2号信号while(1){sigprocmask(SIG_BLOCK, &set, NULL);    // 屏蔽2号信号printf("------------------\n");printf("task is running\n");printf("------------------\n");sleep(1);sigprocmask(SIG_UNBLOCK, &set, NULL);    // 解除2号信号的屏蔽pause();}return 0;
}

正常情况应该是,解除2号信号的屏蔽以后,pause函数挂起的时候捕捉到了信号,此时会先去调用信号处理函数,然后解除挂起就会重新去打印“task is running” 。然而,从下面的结果可以看出,只执行了信号处理函数,但是pause函数没有解除挂起。

原因就是,由于发送信号较为频繁,在打印“task is running” 的时候收到了2号信号,但是此时2号信号被屏蔽了,解除2号信号的屏蔽以后,立马就去调用信号处理函数了,等到pause函数挂起以后,信号就已经处理完了。

因此,当信号发送较为频繁的时候,不建议使用 pause函数 来驱动任务执行。

(2) sigsuspend

sigsuspend 函数被调用以后,直接进入阻塞等待的状态

  • 如果收到了屏蔽信号集中的信号,不予理会,继续挂起
  • 如果收到了屏蔽信号集以外的信号,解除挂起,并调用对应的信号处理函数 或者 执行默认处理行为。

假设 sigsuspend 函数的屏蔽信号集中包含了3号信号,那么sigsuspend收到3号信号就不会解除挂起;如果收到了2号信号,那么sigsuspend函数就会解除挂起,并调用对应的信号处理函数。

#include <stdio.h>
#include <signal.h>
#include <unistd.h>void handler(int signum)
{printf("收到并处理%d号信号\n", signum);
}int main(){signal(2, handler);    // 捕捉2号信号sigset_t set;sigemptyset(&set);      // 清空信号集sigaddset(&set, 2);    // 向信号集中添加2号信号sigset_t mask;        // sigsuspend的屏蔽信号集sigemptyset(&mask);sigaddset(&mask, 3);  // 向屏蔽信号集添加3号信号while(1){sigprocmask(SIG_BLOCK, &set, NULL);    // 屏蔽2号信号printf("------------------\n");printf("task is running\n");printf("------------------\n");sleep(1);sigsuspend(&mask);    // 挂起状态:将进程屏蔽字替换为屏蔽信号集mask// 解除挂起:恢复原本的进程屏蔽字 }return 0;
}

sigsuspend之所以不会像pause那样,是因为sigsuspend函数解除挂起以后的动作是原子的,解除挂起以后,再调用信号处理函数,保证了下一次任务的执行;pause采用的方式是先解除屏蔽,再解除挂起,这就存在一个问题,如果信号在解除挂起之前就被处理了,那么pause函数根本就收不到信号。

信号驱动任务执行(pause、sigsuspend函数)相关推荐

  1. sigsuspend函数(mysleep函数的改进)

    可以通过设置屏蔽SIGALRM的方法来控制程序执行逻辑,但无论如何设置,程序都有可能在"解除信号屏蔽"与"挂起等待信号"这个两个操作间隙失去cpu资源.除非将这 ...

  2. 10.16 sigsuspend函数

    我们已经学习了如何修改进程的信号掩码,实现指定信号的阻塞与接触阻塞.我们可以使用这一技术来保护临界区域的代码(当在这一段区域内执行代码的时候哦,我们不希望被信号中断),但是如果我们想要接触一个信号的阻 ...

  3. 时序竟态条件分析 sigsuspend函数 Linu系统编程

    简单的自定义sleep函数 #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include< ...

  4. Linux信号实现精确到微秒的sleep函数:通过sigsuspend函数解决时序竞态问题

    原理就是先使用定时器定时,然后再使用pause函数或者sigsuspend函数主动阻塞挂起,最终恢复现场. 如果使用pause函数的话,优点是使用简单,缺点是有可能产生时序竞态,导致进程一直阻塞下去: ...

  5. C语言signal()函数(通过设置一个函数(回调函数)来处理捕获到异常信号时需要执行的操作)

    文章目录 描述 声明 参数 返回值 实例 附加解释 背景知识:C语言中signal函数简介及使用 描述 C 库函数 void (*signal(int sig, void (*func)(int))) ...

  6. UNP Chapter 22 - 信号驱动I/O

    22.1. 概述 信号驱动是指当某个描述字上发生了某个事件时,让内核通知进程. 这里描述的信号驱动不是真正的异步I/O. 第15章描述的非阻塞I/O同样不是异步I/O.在非阻塞I/O中,启动I/O操作 ...

  7. sigprocmask , sigpending 和 sigsuspend函数

    sigprocmask函数: 功能描述: 设定对信号屏蔽集内的信号的处理方式(阻塞或不阻塞). 用法: #include <signal.h> int sigprocmask(int ho ...

  8. Unix/Linux编程:竞态条件与sigsuspend函数

    利用pause和alarm函数实现sleep #include <unistd.h>int pause(void); pause函数使调用进程挂起直到有信号到达.如果信号的处理动作是终止进 ...

  9. sigsuspend()函数 解释

    sigsuspend函数作用 :如果在等待信号发生时希望去休眠,则使用sigsuspend函数是非常合适的 头文件:#include <signal.h> 一个保护临界区代码的错误实例:( ...

最新文章

  1. 刷爆了!这项技术BAT力捧!程序员:我彻底慌了...
  2. mysql猎豹_猎豹网校MySQL数据库
  3. WebSphere MQ----通道
  4. 信息系统项目管理师教材【下载PDF】
  5. 【DirectX12】3.配置FBX_SDK
  6. 微信公众号url服务器在哪里,微信公众号url认证(服务器认证)
  7. 评一本书:C#.net 手机动漫游戏设计教程 (一)
  8. java map传入参数_JAVA中map中参数的添加修改
  9. 一位程序猿面试蚂蚁金服后端的经验总结!
  10. Atitit 命令行执行sql 跨语言 目录 1.1. 无需输入密码,那就不要-p参数即可 1 1.2. 4.使用mysql命令执行 1 1.3. 5.mysql命令执行sql,并将查询结果保存到
  11. 身份证编码与校验码计算规则
  12. 测试方法之JUnit单元测试
  13. win10应用商店无法连接到服务器出错,解决win10应用商店无法登陆提示错误0x80070426的方法...
  14. 关于汉王 唐人笔手写板 打开后间歇性手写程序闪退以及屏幕锁屏或者关闭后手写板自动usb拔出问题
  15. Oracle 转 PG- ERROR: recursive query “t“ column 2 has type character varying(150) in non-recursive t
  16. 红米note3全网通_标注:2015112_官方线刷包_救砖包_解账户锁
  17. IE如何打开兼容模式
  18. 【实训第一天】-开班仪式
  19. 超级玩家全面进化 联想Z5s、Z5 Pro GT 855版、S5 Pro GT发布
  20. 模拟电子技术(六)信号的运算与处理

热门文章

  1. 软件测试之安装数据库
  2. ubuntu 软件推荐
  3. LINUX内核编译(ZT)
  4. 7.STM32C8T6+DHT11在OLED上显示 温度,湿度
  5. java linux 读取文件内容_java访问Linux服务器读取文件
  6. Tesseract-OCR下载和安装
  7. Linux——MySQL安装及配置环境变量
  8. 在JavaScript中实现商品图片的局部放大(放大镜)
  9. 小程序-同步微信运动的步数
  10. ★人眼到底等于多少像素 ?