在Linux的多线程中使用信号机制,与在进程中使用信号机制有着根本的区别,可以说是完全不同。在进程环境中,对信号的处理是,先注册信号处理函数,当信号异步发生时,调用处理函数来处理信号。它完全是异步的(我们完全不知到信号会在进程的那个执行点到来!)。然而信号处理函数的实现,有着许多的限制;比如有一些函数不能在信号处理函数中调用;再比如一些函数read、recv等调用时会被异步的信号给中断(interrupt),因此我们必须对在这些函数在调用时因为信号而中断的情况进行处理(判断函数返回时 enno 是否等于 EINTR)。

  但是在多线程中处理信号的原则却完全不同,它的基本原则是:将对信号的异步处理,转换成同步处理,也就是说用一个线程专门的来“同步等待”信号的到来,而其它的线程可以完全不被该信号中断/打断(interrupt)。这样就在相当程度上简化了在多线程环境中对信号的处理。而且可以保证其它的线程不受信号的影响。这样我们对信号就可以完全预测,因为它不再是异步的,而是同步的(我们完全知道信号会在哪个线程中的哪个执行点到来而被处理!)。而同步的编程模式总是比异步的编程模式简单。其实多线程相比于多进程的其中一个优点就是:多线程可以将进程中异步的东西转换成同步的来处理。
 
1. sigwait函数:
  1. sigwait - wait for a signal
  2. #include <signal.h>
  3. int sigwait(const sigset_t *set, int *sig);
  4. Description
  5. The sigwait() function suspends execution of the calling thread until the delivery of one
  6. of the signals specified in the signal set set. The function accepts the signal (removes
  7. it from the pending list of signals), and returns the signal number in sig.
  8. The operation of sigwait() is the same as sigwaitinfo(2), except that:
  9. * sigwait() only returns the signal number, rather than a siginfo_t structure describing
  10. the signal.
  11. * The return values of the two functions are different.
  12. Return Value
  13. On success, sigwait() returns 0. On error, it returns a positive error number.
从上面的man sigwait的描述中,我们知道:sigwait是同步的等待信号的到来,而不是像进程中那样是异步的等待信号的到来。sigwait函数使用一个信号集作为他的参数,并且在集合中的任一个信号发生时返回该信号值,解除阻塞,然后可以针对该信号进行一些相应的处理。
2. 记住:
     在多线程代码中,总是使用sigwait或者sigwaitinfo或者sigtimedwait等函数来处理信号。
     而不是signal或者sigaction等函数。因为在一个线程中调用signal或者sigaction等函数会改变所有线程中的
     信号处理函数。而不是仅仅改变调用signal/sigaction的那个线程的信号处理函数。
3. pthread_sigmask函数:
   每个线程均有自己的信号屏蔽集(信号掩码),可以使用pthread_sigmask函数来屏蔽某个线程对某些信号的
   响应处理,仅留下需要处理该信号的线程来处理指定的信号。实现方式是:利用线程信号屏蔽集的继承关系
  (在主进程中对sigmask进行设置后,主进程创建出来的线程将继承主进程的掩码)
  1. pthread_sigmask - examine and change mask of blocked signals
  2. #include <signal.h>
  3. int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);
  4. Compile and link with -pthread.
  5. DESCRIPTION
  6. The pthread_sigmask() function is just like sigprocmask(2), with the difference that its use
  7. in multithreaded programs is explicitly specified by POSIX.1-2001.
  8. Other differences are noted in this page.
  9. For a description of the arguments and operation of this function, see sigprocmask(2).
  10. RETURN VALUE
  11. On success, pthread_sigmask() returns 0; on error, it returns an error number.
  12. NOTES
  13. A new thread inherits a copy of its creator's signal mask.
  14. (from man sigprocmask: )
  15. The behavior of the call is dependent on the value of how, as follows.
  16. SIG_BLOCK
  17. The set of blocked signals is the union of the current set and the set argument.
  18. SIG_UNBLOCK
  19. The signals in set are removed from the current set of blocked signals. It is permissible
  20. to attempt to unblock a signal which is not blocked.
  21. SIG_SETMASK
  22. The set of blocked signals is set to the argument set.
  23. If oldset is non-NULL, the previous value of the signal mask is stored in oldset.
  24. If set is NULL, then the signal mask is unchanged (i.e., how is ignored), but the current
  25. value of the signal mask is nevertheless returned in oldset (if it is not NULL).
4. pthread_kill函数:
   在多线程程序中,一个线程可以使用pthread_kill对同一个进程中指定的线程(包括自己)发送信号。注意在多线程中  
  一般不使用kill函数发送信号,因为kill是对进程发送信号,结果是:正在运行的线程会处理该信号,如果该线程没有
 注册信号处理函数,那么会导致整个进程退出。
  1. #include <signal.h>
  2. int pthread_kill(pthread_t thread, int sig);
  3. Compile and link with -pthread.
  4. DESCRIPTION
  5. The pthread_kill() function sends the signal sig to thread, another thread in the same
  6. process as the caller. The signal is asynchronously directed to thread.
  7. If sig is 0, then no signal is sent, but error checking is still performed; this can be
  8. used to check for the existence of a thread ID.
  9. RETURN VALUE
  10. On success, pthread_kill() returns 0; on error, it returns an error number, and no signal
  11. is sent.
  12. ERRORS
  13. ESRCH No thread with the ID thread could be found.
  14. EINVAL An invalid signal was specified.
5. 记住:调用sigwait同步等待的信号必须在调用线程中被屏蔽,并且通常应该在所有的线程中被屏蔽(这样可以保证信号绝不会被送到除了调用sigwait的任何其它线程),这是通过利用信号掩码的继承关系来达到的。
(The semantics of sigwait require that all threads (including the thread calling sigwait) have the signal masked, for
  reliable operation. Otherwise, a signal that arrives not blocked in sigwait might be  delivered to another thread.)
6. 代码示例:
  (from man pthread_sigmask)
  1. #include <pthread.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <signal.h>
  6. #include <errno.h>
  7. /* Simple error handling functions */
  8. #define handle_error_en(en, msg) \
  9. do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
  10. static void * 
    1. sig_thread(void *arg)
  11. {
  12. sigset_t *set = (sigset_t *) arg;
  13. int s, sig;
  14. for (;;) {
  15. s = sigwait(set, &sig);
  16. if (s != 0)
  17. handle_error_en(s, "sigwait");
  18. printf("Signal handling thread got signal %d\n", sig);
  19. }
  20. }
  21. int 
    1. main(int argc, char *argv[])
  22. {
  23. pthread_t thread;
  24. sigset_t set;
  25. int s;
  26. /*
  27. Block SIGINT; other threads created by main() will inherit
  28. a copy of the signal mask.
  29. */
  30. sigemptyset(&set);
  31. sigaddset(&set, SIGQUIT);
  32. sigaddset(&set, SIGUSR1);
  33. s = pthread_sigmask(SIG_BLOCK, &set, NULL);
  34. if (s != 0)
  35. handle_error_en(s, "pthread_sigmask");
  36. s = pthread_create(&thread, NULL, &sig_thread, (void *) &set);
  37. if (s != 0)
  38. handle_error_en(s, "pthread_create");
  39. /*
  40. Main thread carries on to create other threads and/or do
  41. other work
  42. */
  43. pause(); /* Dummy pause so we can test program */
  44. return 0;
  45. }
编译运行情况:
  1. digdeep@ubuntu:~/pthread/learnthread$ gcc -Wall -pthread -o pthread_sigmask pthread_sigmask.c
  2. digdeep@ubuntu:~/pthread/learnthread$ ./pthread_sigmask &
  3. [1] 4170
  4. digdeep@ubuntu:~/pthread/learnthread$ kill -QUIT %1
  5. digdeep@ubuntu:~/pthread/learnthread$ Signal handling thread got signal 3
  6. digdeep@ubuntu:~/pthread/learnthread$ kill -USR1 %1
  7. digdeep@ubuntu:~/pthread/learnthread$ Signal handling thread got signal 10
  8. digdeep@ubuntu:~/pthread/learnthread$ kill -TERM %1
  9. digdeep@ubuntu:~/pthread/learnthread$
  10. [1]+ Terminated ./pthread_sigmask
  11. digdeep@ubuntu:~/pthread/learnthread$
这个例子演示了:通过在主线程中阻塞一些信号,其它的线程会继承信号掩码,然后专门用一个线程使用sigwait函数来同步的处理信号,使其它的线程不受到信号的影响。

linux 信号与多线程的更多相关文章

  1. 【转】 Linux下的多线程编程

    作者:gnuhpc 出处:http://www.cnblogs.com/gnuhpc/原文链接:http://www.cnblogs.com/gnuhpc/archive/2012/12/07/280 ...

  2. Linux下的多线程编程

    1 引言 线程(thread)技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期,solaris是这方面的佼佼者.传统的 Unix也支持线程的概念,但是在一个进程(proces ...

  3. 【转】Linux下的多线程编程

    1 引言 线程(thread)技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期,solaris是这方面的佼佼者.传统的 Unix也支持线程的概念,但是在一个进程(proces ...

  4. 《转》Linux下的多线程编程

    原地址:http://linux.chinaunix.net/doc/program/2001-08-11/642.shtml 1 引言 线程(thread)技术早在60年代就被提出,但真正应用多线程 ...

  5. [转帖]Windows和Linux对决(多进程多线程)

    Windows和Linux对决(多进程多线程) https://blog.csdn.net/world_2015/article/details/44920467 太长了 还没看完.. 还是没太理解好 ...

  6. Linux信号机制

    Linux信号(signal) 机制分析 [摘要]本文分析了Linux内核对于信号的实现机制和应用层的相关处理.首先介绍了软中断信号的本质及信号的两种不同分类方法尤其是不可靠信号的原理.接着分析了内核 ...

  7. Linux C++的多线程编程(转)

    1. 引言 线程(thread)技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期,solaris是这方面的佼佼者.传统的Unix也支持线程的概念,但是在一个进程(proces ...

  8. xenomai内核解析之信号signal(一)---Linux信号机制

    版权声明:本文为本文为博主原创文章,转载请注明出处.如有错误,欢迎指正.博客地址:https://www.cnblogs.com/wsg1100/ 目录 1. Linux信号 1.1注册信号处理函数 ...

  9. 基于linux信号的timeout装饰器

    在做基于ray的分布式任务处理时,偶尔遇到由于ray集群不稳定导致的长时间连接不上,进而导致程序卡死,无法向后端返回任务状态的情况.但是ray的初始化函数本身未实现超时机制,因此设计基于多线程+信号的 ...

随机推荐

  1. Idea热部署jrebel失败

    Idea热部署jrebel

  2. Vysor_v1.6.9

    ---恢复内容开始--- 装系统 D:\home sys 触摸板驱动 1 D:\envs\common\jdk jdk安装 2 DriveTheLife 3 img 4 PCMaster 5 Sogo ...

  3. Laravel中不可逆的加密方法

    1 //对 A 密码使用Bcrypt 加密 2 $password = Hash::make('secret'); 3 4 //你也可直接使用 bcrypt 的 function 5 $passwor ...

  4. css display&&hidden

    display:none与visible:hidden的区别 display:none和visible:hidden都能把网页上某个元素隐藏起来,但两者有区别: display:none ---不为被 ...

  5. Vue 组件中 移动 this.$el 的注意事项

    比如, mounted () { document.body.appendChild(this.$el); // insertAdjacentElement // insertBefore}, 这几行 ...

  6. Oracle11g dump 部分参数解读

    一.Oracle dump expdp CONTENT   ALL  ALL ,将导出对象定义及其所有数据  DATA_ONLY  DATA_ONLY,只导出对象数据  METADATA_ONLY   ...

  7. System.Insert - 插入字符串

    System.Insert - 插入字符串 procedure Insert( Substr: String; {要插入的字符串; 可以是常量} var Dest: String; {源字符串} In ...

  8. 获取jsp选中复选框的id传到后台controller,进行逻辑删除等操作

    逻辑删除设备:(数据表中还有这条记录,不显示出来) 思路: 数据表加个字段display,值为Y/N,只显示display为Y的,删除时,把display的值改为N,就不会显示出来 jsp页面如下图, ...

  9. js 怎样获取div 图片等的宽度,只要值,不要px

    给你的div命名id=“abc”,js中用下面的语句就能获取到js的宽度并赋值给a a=document.all.abc.offsetWidth; 然后通过 alert(a); 就能弹出这个值来了.

  10. DevExpress v17.2新版亮点——VCL篇(二)

    用户界面套包DevExpress v17.2日前终于正式发布,本站将以连载的形式为大家介绍各版本新增内容.本文将介绍了DevExpress VCL v17.2 的新功能,快来下载试用新版本! DPI ...