在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. C/S架构系统自动化测试入门

    所谓C/S架构即Client/Server(客户端/服务器架构).虽然近年来C/S架构产品越来越少,大有被B/S(Browser/Server 浏览器/服务器)架构超越的趋势,但C/S还是有B/S不可 ...

  2. TListBox的项目个数

    function TCustomListBox.GetCount: Integer; begin if Style in [lbVirtual, lbVirtualOwnerDraw] then Re ...

  3. 福大软工 1816:项目UML设计(团队作业三)

    项目UML设计(团队) 团队信息 团队名:第三视角 各成员学号及姓名 姓名 学号 博客链接 张扬(组长) 031602345 http://www.cnblogs.com/sxZhangYang/p/ ...

  4. String类型的注意事项

    1.string类型是可变长字符序列,而vector是集合,存放的是某种类型的可变长序列 2.string类型对象的初始化有多种方式:string str="Hello",是将字符 ...

  5. 静态函数和全局函数都没有this指针

    静态函数和全局函数都没有this指针

  6. anu - browser

    import { oneObject, recyclables, typeNumber } from "./util"; //用于后端的元素节点 export function D ...

  7. Linux 之 tar和nc传文件

    前提: 将 172.16.88.1 上的 test 文件夹传送到 172.16.88.2 上 接收方 ---- 172.16.88.2 $ nc -l > test.tar 9876 为端口号 ...

  8. PAT  说反话-加强版   (20分)

    给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出. 输入格式: 测试输入包含一个测试用例,在一行内给出总长度不超过500 000的字符串.字符串由若干单词和若干空格组成,其中单词是由英文字母 ...

  9. vue 局部引入js插件

    参考:https://blog.csdn.net/zhouzuoluo/article/details/84781490

  10. 1.1.4 A+B for Input-Output Practice (V)

    A+B for Input-Output Practice (V) Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K ...