本文转载自:http://blog.csdn.net/yusiguyuan/article/details/14237277

在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 insig.
  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(inthow, 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 thatits 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 inoldset.
  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 inoldset (if it is not NULL).
4. pthread_kill函数:
   在多线程程序中,一个线程可以使用pthread_kill对同一个进程中指定的线程(包括自己)发送信号。注意在多线程中  
  一般不使用kill函数发送信号,因为kill是对进程发送信号,结果是:正在运行的线程会处理该信号,如果该线程没有
 注册信号处理函数,那么会导致整个进程退出。
  1. #include <signal.h>
  2. int pthread_kill(pthread_tthread, intsig);
  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 sigwaitmight 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. /* Simpleerror 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/ordo
  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函数来同步的处理信号,使其它的线程不受到信号的影响。

  1. #include <pthread.h>
  2. #include <stdio.h>
  3. #include <sys/signal.h>
  4. #define NUMTHREADS 3
  5. void sighand(int signo);
  6. void *threadfunc(void *parm)
  7. {
  8. pthread_t             tid = pthread_self();
  9. int                   rc;
  10. printf("Thread %u entered\n", tid);
  11. rc = sleep(3);
  12. printf("Thread %u did not get expected results! rc=%d\n", tid, rc);
  13. return NULL;
  14. }
  15. void *threadmasked(void *parm)
  16. {
  17. pthread_t             tid = pthread_self();
  18. sigset_t              mask;
  19. int                   rc;
  20. printf("Masked thread %lu entered\n", tid);
  21. sigfillset(&mask); /* Mask all allowed signals */
  22. //  sigemptyset(&mask);
  23. rc = pthread_sigmask(SIG_BLOCK, &mask, NULL);
  24. if (rc != 0)
  25. {
  26. printf("%d, %s\n", rc, strerror(rc));
  27. return NULL;
  28. }
  29. rc = sleep(1);
  30. if (rc != 0)
  31. {
  32. printf("Masked thread %lu did not get expected results! ""rc=%d \n",tid, rc);
  33. return NULL;
  34. }
  35. //  sigwait(&mask,&rc);
  36. printf("Masked thread %lu completed masked work\n",tid);
  37. return NULL;
  38. }
  39. int main(int argc, char **argv)
  40. {
  41. int                     rc;
  42. int                     i;
  43. struct sigaction        actions;
  44. pthread_t               threads[NUMTHREADS];
  45. pthread_t               maskedthreads[NUMTHREADS];
  46. printf("Enter Testcase - %s\n", argv[0]);
  47. printf("Set up the alarm handler for the process\n");
  48. memset(&actions, 0, sizeof(actions));
  49. sigemptyset(&actions.sa_mask);
  50. actions.sa_flags = 0;
  51. actions.sa_handler = sighand;
  52. rc = sigaction(SIGALRM,&actions,NULL);
  53. printf("Create masked and unmasked threads\n");
  54. for(i=0; i<NUMTHREADS; ++i)
  55. {
  56. rc = pthread_create(&threads[i], NULL, threadfunc, NULL);
  57. if (rc != 0)
  58. {
  59. printf("%d, %s\n", rc, strerror(rc));
  60. return -1;
  61. }
  62. rc = pthread_create(&maskedthreads[i], NULL, threadmasked, NULL);
  63. if (rc != 0)
  64. {
  65. printf("%d, %s\n", rc, strerror(rc));
  66. return -1;
  67. }
  68. }
  69. sleep(5);
  70. printf("Send a signal to masked and unmasked threads\n");
  71. for(i=0; i<NUMTHREADS; ++i)
  72. {
  73. rc = pthread_kill(threads[i], SIGALRM);
  74. rc = pthread_kill(maskedthreads[i], SIGALRM);
  75. }
  76. printf("Wait for masked and unmasked threads to complete\n");
  77. for(i=0; i<NUMTHREADS; ++i) {
  78. rc = pthread_join(threads[i], NULL);
  79. rc = pthread_join(maskedthreads[i], NULL);
  80. }
  81. printf("Main completed\n");
  82. return 0;
  83. }
  84. void sighand(int signo)
  85. {
  86. pthread_t             tid = pthread_self();
  87. printf("Thread %lu in signal handler\n",tid);
  88. return;
  89. }

(ps:由上面的几篇文章可知,线程中的信号处理机制和进程中的信号处理机制是不同的,或者说是完全不同的,一般在多线程中使用信号的,或单独启动一个线程类处理信号,在主进程中发送信号,在主进程中使用了pthread_mask()函数来处理信号屏蔽信息,这个时候在主进程中使用kill,这个时候线程也是可以接受到信号的原因是pthread_mask继承了主进程的信号屏蔽信息,这个时候也是可以在使用pthread_kill给相应的线程发送相应的信号,但是在有的程序中,在线程中使用pthread_mask,这个使用就必须使用pthread_kill来发送信号了;但是在进程中的信号机制没有这么复杂,进程中只需要注册一个函数,就静静的等待信号处理。不过在进程中使用的方法也是可以在线程中使用的)

多线程中的信号机制--signwait()函数【转】的更多相关文章

  1. Linux内核中的信号机制--一个简单的例子【转】

    本文转载自:http://blog.csdn.net/ce123_zhouwei/article/details/8562958 Linux内核中的信号机制--一个简单的例子 Author:ce123 ...

  2. linux中的信号机制

    概述 Linux信号机制是在应用软件层次上对中断机制的一种模拟,信号提供了一种处理异步事件的方法,例如,终端用户输入中断键(ctrl+c),则会通过信号机制停止一个程序[1]. 这其实就是向那个程序( ...

  3. Qt在多线程中使用信号槽的示例

    之前对线程理解得不深入,所以对Qt的线程机制没有搞清楚,今天写一篇文章总结一下,如有错误,欢迎指出. 首先需要理解线程是什么,线程在代码中的表现其实就是一个函数,只不过这个函数和主线程的函数同时运行, ...

  4. java中的异常处理机制_函数覆盖时的异常特点

    /*注意:异常声明在函数上 异常在子父类覆盖时的体现1.子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者异常的子类2.如果父类方法抛出多个异常,那么子类在覆盖该方法 ...

  5. Rust多线程中的消息传递机制

    代码说话. use std::thread; use std::sync::mpsc; use std::time::Duration; fn main() { let (tx, rx) = mpsc ...

  6. linux信号机制与python信号量

    1.信号本质 软中断信号(signal,又简称为信号)用来通知进程发生了异步事件.在软件层次上是对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的.信号是进程间 ...

  7. Linux信号机制

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

  8. 处理python中的信号

    什么是信号 信号(signal)-- 进程间通讯的一种方式,也可作为一种软件中断的方法.一个进程一旦接收到信号就会打断原来的程序执行来按照信号进行处理. 简化术语,信号是一个事件,用于中断运行功能的执 ...

  9. Qt多线程编程中的对象线程与函数执行线程

    近来用Qt编写一段多线程的TcpSocket通信程序,被其中Qt中报的几个warning搞晕了,一会儿是说“Cannot create children for a parent that is in ...

随机推荐

  1. Spring Data JPA(官方文档翻译)

    关于本书 介绍 关于这本指南 第一章 前言 第二章 新增及注意点 第三章 项目依赖 第四章 使用Spring Data Repositories 4.1 核心概念 4.2 查询方法 4.3 定义rep ...

  2. idea 创建的maven+spring+mybatis项目整合 报错无法创建bean

    报错如下: Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with n ...

  3. Roadblocks--poj3255(次短路)

    题目链接 求次短路的问题: dist[i][0]和dist[i][1]表示从起点1到i的距离和从起点n到i的距离: 次短路要比最短路大但小于其他路: 每条路1--n的距离都可以用dist[i][0] ...

  4. 洛谷P2679 子串 [noip2015] dp

    正解:dp 解题报告: 感觉是道dp好题啊,所以就写了个题解 代码实现难度低,思维难度大,像我这种思维僵化傻逼选手只想到了爆搜+组合数学... 其实是道很妙的dp题!好趴也没有多妙主要大概是妙在想到了 ...

  5. BZOJ4614 UVA1742 Oil 计算几何+搜索+扫描线

    正解:计算几何+搜索+扫描线 解题报告: 传送门 哇我是真的觉得这题很妙了!各个方面都很妙啊... 首先有一个很重要的结论:最优线一定可以通过各种变换(旋转/平移)使得经过一条线段的左端点(...并不 ...

  6. epoll详细工作原理(转)

    原文:没有找到出处 开发高性能网络程序时,windows开发者们言必称iocp,linux开发者们则言必称epoll.大家都明白epoll是一种IO多路复用技术,可以非常高效的处理数以百万计的sock ...

  7. 查看win信任的证书办法机构(CA机构的公钥)

    cmd mmc

  8. 自增ID时如何插入ID

    自增ID时如何插入ID SET IDENTITY_INSERT TABLE_NAME ON; INSERT INTO TABLE_NAME(XXX, XXX,..., XXX) SELECT XXX, ...

  9. 高性能MySQL中的三星索引

    高性能MySQL中的三星索引 我对此提出了深深的疑问: 一星:相关的记录指的是什么??(相关这个词很深奥,“相关部门”是什么部门) 二星:如果建立了B-Tree(B+Tree)索引,数据就有序了.三星 ...

  10. Session实例

    Session常用方法(一) session对象用来保存一些在与每个用户回话期间需要保存的数据信息,这样就方便了回话期间的一些处理程序.如可以用session变量记住用户的用户名,以后就不必在其他的网 ...