在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. 068——VUE中vuex的使用场景分析与state购物车实例

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. HeadFirstJava

    java执行过程的来龙去脉 源代码——编译器——输出——java虚拟机 扩展名为.java ——扩展名为.class 不要直接用类名点变量来改变属性值,一般都用get.set方法.封装的基本原则:将你 ...

  3. 多种方法实现 python 线程池

    最近在做一个爬虫相关的项目,单线程的整站爬虫,耗时真的不是一般的巨大,运行一次也是心累,,,所以,要想实现整站爬虫,多线程是不可避免的,那么python多线程又应该怎样实现呢?这里主要要几个问题(关于 ...

  4. XML解析之XPath

    body, table{font-family: 微软雅黑; font-size: 10pt} table{border-collapse: collapse; border: solid gray; ...

  5. L1-027 出租

    下面是新浪微博上曾经很火的一张图: 一时间网上一片求救声,急问这个怎么破.其实这段代码很简单,index数组就是arr数组的下标,index[0]=2 对应 arr[2]=1,index[1]=0 对 ...

  6. C++内存管理的原则

    内存管理原则,就是“谁创建,谁释放”或者说“谁申请,谁释放”. 简单地说,在代码上体现为,调用new或malloc等内存分配的人,同时需在内存使用完成后调用delete或free释放. 这个原则看似大 ...

  7. SVN使用出现的问题及解决方案

    SVN使用出现的问题及解决方案 一.问题描述: 使用TortoiseSVN-1.9.5进行CheckOut时,出现报错信息如下:  Unable to connect to a repository ...

  8. 神经网络损失函数中的正则化项L1和L2

    神经网络中损失函数后一般会加一个额外的正则项L1或L2,也成为L1范数和L2范数.正则项可以看做是损失函数的惩罚项,用来对损失函数中的系数做一些限制. 正则化描述: L1正则化是指权值向量w中各个元素 ...

  9. Samsung_tiny4412(驱动笔记08)----jiffies,timer,kthread,workqueue,tasklet

    /*********************************************************************************** * * jiffies,tim ...

  10. 51Nod 1072:威佐夫游戏 (威佐夫博奕)

    1072 威佐夫游戏  基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 有2堆石子.A B两个人轮流拿,A先拿.每次可以从一堆中取任意个或从2堆中取相同数 ...