sigwait()函数

线程可以通过调用sigwait等待一个或多个信号发生。

函数原型:

#include<signal.h>
int sigwait(const sigset_t *restrict set,int *restrict signop);

                                                                                                 返回值:若成功则返回0,否则返回错误编号

set参数指出了线程等待的信号集,signop指向的整数将作为返回值,表明发送信号的数量。

如果信号集中的某个信号在sigwait调用的时候处于未决状态,那么sigwait将无阻塞发生,在返回之前,sigwait将从进程中移除那些处于未决状态的信号。为了避免错误动作发生,线程在调用sigwait之前,必须阻塞那些它正在等待的信号。sigwait会自动取消信号集的阻塞状态,直到有新的信号被递送。在返回之前,sigwait将恢复线程的信号屏蔽字。如果信号在sigwait调用的时候没有被阻塞,在完成对sigwait调用之前会出现一个时间窗,在这个窗口期,某个信号可能在线程完成sigwait调用之前就被递送了。

使用sigwait的好处在于它可以简化信号处理,允许把异步产生的信号用同步的方式处理。为了防止信号中断线程,可以吧信号加到每个线程的信号屏蔽字中,然后安排专用线程做信号处理。这些专用线程可以进行函数调用,不需要担心在信号处理程序中调用哪些函数是安全的,因为这些函数调用来自正常的线程环境,而非传统的信号处理程序,传统信号处理程序通常会中断线程的正常执行。

如果多个线程在sigwait调用时,等待的是同一个信号,这时就会出现线程阻塞。当信号递送的时候,只有一个线程可以从sigwait中返回。如果信号被捕获(例如进程通过使用sigaction建立了一个信号处理程序),而且线程正在sigwait调用中等待同一信号,那么这时将由操作系统实现来决定以何种方式递送信号。在这种情况下,操作系统实现可以让sigwait返回,也可以激活信号处理程序,但不可能出现两者皆可的情况。

1. sigwait函数:
sigwait等一个或者多个指定信号发生。
    它所做的工作只有两个:第一,监听被阻塞的信号;第二,如果所监听的信号产生了,则将其从未决队列中移出来(这里实时信号和非实时信号又有区别,体现在取出的顺序等,具体自己取网上查,这里不再详述)。sigwait并不改变信号掩码的阻塞与非阻塞状态。
    在POSIX标准中,当进程收到信号时,如果是多线程的情况,我们是无法确定是哪一个线程处理这个信号。而sigwait是从进程中pending的信号中,取走指定的信号。这样的话,如果要确保sigwait这个线程收到该信号,那么所有线程含主线程以及这个sigwait线程则必须block住这个信号,因为如果自己不阻塞就没有未决状态(阻塞状态)信号,别的所有线程不阻塞就有可能当信号过来时,被其他的线程处理掉

记住:
     在多线程代码中,总是使用sigwait或者sigwaitinfo或者sigtimedwait等函数来处理信号。
     而不是signal或者sigaction等函数。因为在一个线程中调用signal或者sigaction等函数会改变所以线程中的信号处理函数,而不是仅仅改变调用signal/sigaction的那个线程的信号处理函数。

进程中使用信号机制与线程中使用信号机制的区别

在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 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. /* Simpleerror handling functions*/

  8. #define handle_error_en(en, msg)\
  9.         do {  errno= en; perror(msg);exit(EXIT_FAILURE)<
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值