12.8 线程和信号


在基于进程模型的信号处理已经比较吗麻烦了,引入线程后事情就更加复杂了。
每个线程拥有其自身的信号掩码,但是信号处理函数是被进程内的所有线程共享的,作为一个推论,独立的线程能够阻塞信号,但是如果一个线程修改与给定信号的处理动作的时候,所有的线程都会共享这一修改。也就是说,如果一个线程选择忽略一个给定信号,其他的线程可能会通过恢复默认呢处理或者是安装信号处理函数的方式撤销线程所做的忽略选择。
信号会只会被发送到进程内的一个线程。如果信号与硬件错误相关,那么信号通常被发送到造成时间发生的线程,其他信号,将被发送到任意一个线程。
在10.12节中,我们介绍了进程可以使用函数sigprocmask函数来阻塞信号的发送,然而,sigprocmask函数在多线程进程中的行为是未定义的,线程必须使用函数pthread_sigmask予以代替。

  1. #include <signal.h>
  2. int pthread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);
  3. Returns: 0 if OK, error number on failure.

函数pthread_sigmask与函数sigprocmask相似,但是pthread_sigmask函数在失败的时候返回一个错误码,而函数sigprocmask在失败的时候返回-1并且设置errno变量。
参数how可以取三个不同的数值:
* SIG_BLOCK添加信号集到线程的信号掩码中;
* SIG_SETMASK使用信号集替换线程的信号掩码;
* SIG_UNBLOCK从线程的信号掩码中移除信号集;
如果oset参数不是null,那么线程的前一个信号掩码将被存储到oset指针指向的内存中。线程可以通过设置set参数为null的情况下获取其当前的信号掩码,着这种情况下,how参数将被忽略。

线程可以调用函数sigwait来等待一个或者多个信号的出现;

  1. #include <signal.h>
  2. int sigwait(const sigset_t *restrict set, int *restrict signop);
  3. Returns: 0 if OK, error number on failure.

参数set指定了线程正在等待信号的集合,参数signop指针指向的内存将会存储被发送的信号数量。
如果在sigwait函数被调用的时候,如果set中的一个信号处于挂起状态,那么函数sigwait就不会阻塞,而是直接返回,在返回之前,sigwait函数将会将从进程挂起的信号集中移除等到的信号。如果实现支持信号排队,并且一个信号的多个实例处于挂起状态,函数sigwait仅仅移除其中一个实例,其他实例仍然处于排队状态。
为了避免错误的行为,线程在调用函数sigwait之前必须先阻塞这些等待的信号。函数sigwait将会自动解除对应信号的阻塞,并且一直等待知道其中一个信号被发送,在返回之前,sigwait将会恢复线程的信号掩码,如果函数sigwait被调用的时候,对应的信号没有被阻塞,那么在完成函数sigwait之前会出现一个多于的时间窗口,在这个时间窗口内,信号可能被发送到了线程。
使用函数sigwait的一个好处就是可以简化信号处理函数的设计,因为它允许我们将异步信号处理当作是同步信号来看待,我们可以通过将指定信号添加到线程的信号掩码中,从而防止信号中断线程的执行,然后专门指定一个线程来处理信号,这些指定的线程在调用函数的时候不需要再考虑那些函数是信号处理安全的,因为在信号处理函数被调用的时候,线程处于正常的线程环境,而不是像传统情况那样:信号处理函数能够中断线程的正常执行。
如果多个线程由于调用了函数sigwait而阻塞在了同一个信号上,那么当信号被发送的时候,仅仅只有一个线程将会返回,如果一个信号被捕获,并且存在一个线程调用函数sigwait等待这一信号,如何发送信号是交给实现了决定的,实现可以允许sigwait返回或者是调用信号处理函数,但是不能同时执行这两个动作。
为了发送一个信号给进程,我们可以调用函数kill,为了发送一个信号给一个线程,我们可以调用函数pthread_kill;

  1. #include <signal.h>
  2. int pthread_kill(pthread_t thread, int signl);
  3. Returns: 0 if ok, error number on failure.

我们可以传递给参数signo数值0,用于检测指定线程是否存在。如果一个信号的默认处理方式是终止进程,那么向一个线程发送这个信号也会终止掉整个进程。
注意alarm timers是进程资源,所有的线程都会共享相同的alarms集合,因此,对于一个进程中的多个线程,不可能做到使用alarm timers而不发生冲突。

Example

在图10.23中,我们等待信号处理函数设置一个标志,用于表示主程序可以退出了。在这个程序中,可以运行的程序流仅仅只有主线程以及信号处理函数,所以阻塞信号对于避免丢失标志的改变是有效的。使用多线程以后,我们需要使用互斥锁来保护标志,正如在图12.16中程序所示。

  1. #include "apue.h"
  2. #include <pthread.h>
  3. int quitflag; /* set nonzero by thread */
  4. sigset_t mask;
  5. pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
  6. pthread_cond_t waitloc = PTHREAD_COND_INITIALIZER;
  7. void *thr_fn(void *arg)
  8. {
  9. int err, signo;
  10. for(;;)
  11. {
  12. err = sigwait(&mask, &signo);
  13. if(err != 0)
  14. err_exit(err, "sigwait failed");
  15. switch(signo)
  16. {
  17. case SIGINT:
  18. printf("\ninterrupt\n");
  19. break;
  20. case SIGQUIT:
  21. pthread_mutex_lock(&lock);
  22. quitflag = 1;
  23. pthread_mutex_unlock(&lock);
  24. pthread_cond_signal(&waitloc);
  25. return (0);
  26. default:
  27. printf("unexpected signal %d\n", signo);
  28. exit(1);
  29. }
  30. }
  31. }
  32. int main(void)
  33. {
  34. int err;
  35. sigset_t oldmask;
  36. pthread_t tid;
  37. sigemptyset(&mask);
  38. sigaddset(&mask, SIGINT);
  39. sigaddset(&mask, SIGQUIT);
  40. if((err = pthread_sigmask(SIG_BLOCK, &mask, &oldmask)) != 0)
  41. err_exit(err, "SIG_BLOCK error");
  42. err = pthread_create(&tid, NULL, thr_fn, 0);
  43. if(err != 0)
  44. {
  45. err_exit(err, "can;t create thread");
  46. }
  47. pthread_mutex_lock(&lock);
  48. while(quitflag == 0)
  49. pthread_cond_wait(&waitloc, &lock);
  50. pthread_mutex_unlock(&lock);
  51. /*SIGQIUT has been caught and is now blocked; do whatever */
  52. quitflag = 0;
  53. /*reset signal mask which unblocks ISGQUIT */
  54. if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
  55. err_sys("SIG_SETMASK error");
  56. exit(0);
  57. }

图12.16 同步信号处理
信号处理函数不再会中断主线程,我们使用一个专门的线程来处理信号,我们可以在互斥锁的保护下修改quitflag,so that the main thread of control can’t miss the wake-up call made when we call pthread_cond_signal.我们在主线程中使用同一互斥锁来检查标记的值,并在我们等待条件的时候自动释放锁。
注意同时阻塞了信号SIGINT以及SIGQUIT信号,当我们创建线程来处理信号的时候,线程继承了当前的信号掩码,因为sigwait并不会阻塞信号,因此只有一个线程可以接受信号,这样可以使得我们在编写主线程的时候不用考虑这些中断信号的干扰。
程序运行情况如下入所示:

  1. yuekunhu@debian:~/APUE/chapter12$ ./12_16.exe
  2. ^C
  3. interrupt
  4. ^C
  5. interrupt
  6. ^C
  7. interrupt
  8. ^\yuekunhu@debian:~/APUE/chapter12$



来自为知笔记(Wiz)


转载于:https://www.cnblogs.com/U201013687/p/5635947.html

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

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

相关文章

基于MVC的网站和在线教育系统

最近老表说要创业&#xff0c;想要做一个网站做宣传&#xff0c;还想要一个在线教育系统。 学习了一部分 Java&#xff0c; 决定用.Net MVC做官网或直接做成静态HTML网站&#xff0c;主要是因为.Net MVC 技术简单&#xff0c;效率高&#xff0c;需求不确定。 考虑的点在&#…

密码学经典之生日悖论与生日攻击【详解】

生日悖论 在算法导论书上看到个比较有意思的概率算法&#xff0c;在这里加上自己的理解分享下&#xff1a; 上次刚看同学发的朋友圈说道&#xff1a;“两个人同一间宿舍&#xff0c;而且同年同月同日生&#xff0c;这个缘分真的是醉了”&#xff0c;当时我也是醉醉的&#xff…

matlab simplify,[求助]Matlab2016b里没有simple函数

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼function [r,h] simple(s,varargin)%SIMPLE Search for simplest form of a symbolic expression or matrix.% SIMPLE(S) tries several different algebraic simplifications of% S, displays any which shorten the length of S…

网龙面试后多久有回应_回应面试问题

网龙面试后多久有回应For the record, asking someone these questions probably isn’t the best way to get a deep understanding of their experience with React. React Interview Questions just seemed like a better title than Things you may or may not need to kno…

Bagging与随机森林算法原理小结

在集成学习原理小结中&#xff0c;我们讲到了集成学习有两个流派&#xff0c;一个是boosting派系&#xff0c;它的特点是各个弱学习器之间有依赖关系。另一种是bagging流派&#xff0c;它的特点是各个弱学习器之间没有依赖关系&#xff0c;可以并行拟合。本文就对集成学习中Bag…

iOS:多线程技术GCD的使用

GCD的使用&#xff1a; 1.队列的类型1.1 主队列&#xff1a;mian queue,主线程队列,负责更行UI的操作。是一个串行的队列。1.2 系统默认的并行队列&#xff1a;global queue&#xff0c;按优先级分类。1.3 自定义的队列&#xff1a;可以创建串行队列或者是并行的队列2.任务2.1 …

java什么叫一致性,java-顺序一致性易失性说明

我正在从Java Jpoint会议观看视频.我对以下来自Alexey Shipilev报告的幻灯片有疑问&#xff1a;打扰一下,请不要打扰我.实际上,作者说不可能将变量集设置为r1 1 (Y)r2 0 (x)r3 1 (x)r4 0 (Y)根据视频,他暗示很明显.有人可以澄清为什么JMM无法设置此值吗&#xff1f;附言如果…

模块制作标准说明

原则一&#xff1a;CSS定义越少越好原则二&#xff1a;进来用<ul><li>等简单的HTML代码结构原则三&#xff1a;命名尽可能用CSS伪类原则四&#xff1a;一个模块CSS名称不能超过三个需要改正的写法&#xff1a; <div class"fenglei"><div class&…

【c++】string类的使用

目录 一、标准库中的string类 1、简单介绍string类 2、string类的常用接口注意事项 2.1、string类对象的常用构造 2.2、string类对象的容量操作 2.3、string类对象的访问及遍历操作 2.4、string类对象的修改操作 二、string类的模拟实现 一、标准库中的string类 1、简…

拜托了

by Buddy Reno由Buddy Reno Git Please &#xff1a;如何在不做蠢事的情况下强行推动 (Git Please: how to force push without being a jerk) As the size of a dev team grows, so does the likelihood of someone doing a force push and overwriting someone else’s code…

性能测试类型

1.验收性能测试 验收性能测试&#xff08;Acceptance Performance Testing&#xff09;方法通过模拟生产运行的业务压力量和使用场景组合&#xff0c;测试系统的性能是否满足生产性的要求。通俗的说&#xff1a;在特定的运行条件下验证系统的能力状况。 &#xff08;1&#xff…

Java - 对象(object) 具体解释

对象(object) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/24059545 对象(object)的实例能够是 物理对象(如 人, 车等实物) 或 逻辑对象(如 运动, 健康等); 对象是将状态(数据) 和行为(功能) 组合在一起的软件模块. 类是描写叙述一组相似对象共同…

kkt条件的matlab仿真,请教关于SVM中KKT条件的推导

KKT条件第一项是说最优点必须满足所有等式及不等式限制条件&#xff0c;也就是说最优点必须是一个可行解&#xff0c;这一点自然是毋庸置疑的。第二项表明在最优点 x*&#xff0c; ∇f 必須是 ∇hj 和 ∇gk 的线性組合&#xff0c;和都叫作拉格朗日乘子。所不同的是不等式限制条…

公共wifi做家用_如何在公共网络上获得免费的wifi

公共wifi做家用by Kyle McDonald凯尔麦克唐纳(Kyle McDonald) 如何在公共网络上获得免费的wifi (How to get free wifi on public networks) This short tutorial describes a few methods for gaining access to the internet, a basic human right, from public wireless ne…

python学习之旅

一、入门 1.Python 面向对象编程 2.jquery入门 3.HTMLCSS基础入门 4.Javascript初步 5.Python语言编程基础 二、初级阶段 1.Git 与 GitHub 2.Python 爬虫基础 3.django进阶 4.django项目部署 5.ajax入门 6.django基础 7.Mysql基础 三、中级阶段 1.Linux基础 2.Python :socket a…

c/c++ 重载运算符 函数调用运算符

重载运算符 函数调用运算符 把一个类的对象a&#xff0c;当成函数来使用&#xff0c;比如a()&#xff0c;所以需要重载operator()方法。重载了函数调用运算符的类的对象&#xff0c;就是函数对象了。 还有什么是函数对象呢&#xff1f;&#xff1f;&#xff1f; lambda是函数对…

matlab 万能,matlab 万能实用的线性曲线拟合方法

在科学计算和工程应用中&#xff0c;经常会遇到需要拟合一系列的离散数据&#xff0c;最近找了很多相关的文章方法&#xff0c;在这里进行总结一下其中最完整、几乎能解决所有离散参数线性拟合的方法第一步&#xff1a;得到散点数据根据你的实际问题得到一系列的散点例如&#…

socket websocket

1.websocket客户端 websocket允许通过JavaScript建立与远程服务器的连接&#xff0c;从而实现客户端与服务器间双向的通信。在websocket中有两个方法&#xff1a;      1、send() 向远程服务器发送数据    2、close() 关闭该websocket链接  websocket同时还定义了几…

javascript原型_JavaScript的原型:古怪,但这是它的工作原理

javascript原型by Pranav Jindal通过普拉纳夫金达尔 JavaScript的原型&#xff1a;古怪&#xff0c;但这是它的工作原理 (Prototype in JavaScript: it’s quirky, but here’s how it works) The following four lines are enough to confuse most JavaScript developers:以下…

mysql函数之SUBSTRING_INDEX(str,/,-1)

SUBSTRING_INDEX的用法&#xff1a; •SUBSTRING_INDEX(str,delim,count) 在定界符 delim 以及count 出现前&#xff0c;从字符串str返回自字符串。若count为正值,则返回最终定界符(从左边开始) 若为-1则是从后往前截取 SELECT substring_index(Hn_P00001, P, -1) -- 结果是…