在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. Python中简化的验证码功能实现

    #!/usr/bin/env python # _*_ encoding:utf-8 _*_ # author:snate import random def generate_auth_code() ...

  2. HTML5之pushstate、popstate操作history,无刷新改变当前url

    一.认识window.history window.history表示window对象的历史记录,是由用户主动产生,并且接受javascript脚本控制的全局对象.window对象通过history对 ...

  3. SharePoint 2013的100个新功能之内容管理(一)

    一:拖拽 现在在任意的文档库中,你可以拖拽文档到文档库区域,它会以进度条显示上传到文档库中.第一步鼠标点击文档拖动到文档库区域时,它会变成"拖到此处",第二步放开鼠标,上传. 二: ...

  4. L219 China's office workers consider further education, training essential

    More than 90 percent of China's office workers consider on-the-job training and continuing education ...

  5. 一起来点React Native——常用组件之TextInput

    一.前言 文本输入框,相当于OC中的UITextField,在用法和属性方面,两者都有很大的借鉴之处:通过键盘将文本输入到应用程序的一个基本的组件: 二.TextInput的常见属性 因为TextIn ...

  6. Python入门——第一个Python程序

    1.1 Hello Python书写步骤 步骤一:新建文本文档文件,修改名称为hello.py 步骤二:使用记事本打开文件,书写程序内容如下: print("hello python&quo ...

  7. led不同颜色的驱动电压和驱动电流

    LED耗电非常低,一般来说LED的工作电压是2-3.6V,其中红光电压是1.8-2.1V 波长610-620    绿光电压是3.0-3.5V 波长520-530   兰光电压是3.0-3.5V 波长 ...

  8. Unity 3D编辑器扩展介绍、教程(一) —— 创建菜单项

    Unity编辑器扩展教程 本文提供全流程,中文翻译.Chinar坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) 一 Brief Introduct ...

  9. 斐波那契数列的5种python实现写法

    斐波那契数列的5种python写法       斐波那契数列(Fibonacci sequence),又称黄金分割数列.因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖 ...

  10. 对象Date的方法

    Date()对象是js提供给我们的日期对象,可以利用它获取关于时间的量. var myDate = new Date() //首先构造一个时间对象,然后用对象的方法获取时间: 1.获取年份: var ...