在Linux的多線程中使用信號(hào)機(jī)制,與在進(jìn)程中使用信號(hào)機(jī)制有著根本的區(qū)別,可以說(shuō)是完全不同。在進(jìn)程環(huán)境中,對(duì)信號(hào)的處理是,先注冊(cè)信號(hào)處理函數(shù),當(dāng)信號(hào)異步發(fā)生時(shí),調(diào)用處理函數(shù)來(lái)處理信號(hào)。它完全是異步的(我們完全不知到信號(hào)會(huì)在進(jìn)程的那個(gè)執(zhí)行點(diǎn)到來(lái)!)。然而信號(hào)處理函數(shù)的實(shí)現(xiàn),有著許多的限制;比如有一些函數(shù)不能在信號(hào)處理函數(shù)中調(diào)用;再比如一些函數(shù)read、recv等調(diào)用時(shí)會(huì)被異步的信號(hào)給中斷(interrupt),因此我們必須對(duì)在這些函數(shù)在調(diào)用時(shí)因?yàn)樾盘?hào)而中斷的情況進(jìn)行處理(判斷函數(shù)返回時(shí)
enno 是否等于 EINTR)。
但是在多線程中處理信號(hào)的原則卻完全不同,它的基本原則是:將對(duì)信號(hào)的異步處理,轉(zhuǎn)換成同步處理,也就是說(shuō)用一個(gè)線程專(zhuān)門(mén)的來(lái)“同步等待”信號(hào)的到來(lái),而其它的線程可以完全不被該信號(hào)中斷/打斷(interrupt)。這樣就在相當(dāng)程度上簡(jiǎn)化了在多線程環(huán)境中對(duì)信號(hào)的處理。而且可以保證其它的線程不受信號(hào)的影響。這樣我們對(duì)信號(hào)就可以完全預(yù)測(cè),因?yàn)樗辉偈钱惒降模峭降模?span style="color:#000080">我們完全知道信號(hào)會(huì)在哪個(gè)線程中的哪個(gè)執(zhí)行點(diǎn)到來(lái)而被處理!)。而同步的編程模式總是比異步的編程模式簡(jiǎn)單。其實(shí)多線程相比于多進(jìn)程的其中一個(gè)優(yōu)點(diǎn)就是:多線程可以將進(jìn)程中異步的東西轉(zhuǎn)換成同步的來(lái)處理。
1. sigwait函數(shù):
- sigwait - wait for a signal
- #include <signal.h>
- int sigwait(const sigset_t *set, int *sig);
Description - The sigwait() function suspends execution of the calling thread until the delivery of one
- of the signals specified in the signal set set. The function
accepts the signal (removes
- it from the pending list of signals), and returns the signal number in
sig.
- The operation of sigwait() is the same as sigwaitinfo(2), except that:
- * sigwait() only returns the signal number, rather than a siginfo_t structure describing
- the signal.
- * The return values of the two functions are different.
- Return Value
- On success, sigwait() returns 0. On error, it returns a positive error number.
從上面的man sigwait的描述中,我們知道:sigwait是同步的等待信號(hào)的到來(lái),而不是像進(jìn)程中那樣是異步的等待信號(hào)的到來(lái)。sigwait函數(shù)使用一個(gè)信號(hào)集作為他的參數(shù),并且在集合中的任一個(gè)信號(hào)發(fā)生時(shí)返回該信號(hào)值,解除阻塞,然后可以針對(duì)該信號(hào)進(jìn)行一些相應(yīng)的處理。
2. 記?。?/span>
在多線程代碼中,總是使用sigwait或者sigwaitinfo或者sigtimedwait等函數(shù)來(lái)處理信號(hào)。
而不是signal或者sigaction等函數(shù)。因?yàn)樵谝粋€(gè)線程中調(diào)用signal或者sigaction等函數(shù)會(huì)改變所以線程中的
信號(hào)處理函數(shù)。而不是僅僅改變調(diào)用signal/sigaction的那個(gè)線程的信號(hào)處理函數(shù)。
3. pthread_sigmask函數(shù):
每個(gè)線程均有自己的信號(hào)屏蔽集(信號(hào)掩碼),可以使用pthread_sigmask函數(shù)來(lái)屏蔽某個(gè)線程對(duì)某些信號(hào)的
響應(yīng)處理,僅留下需要處理該信號(hào)的線程來(lái)處理指定的信號(hào)。實(shí)現(xiàn)方式是:利用線程信號(hào)屏蔽集的繼承關(guān)系
(在主進(jìn)程中對(duì)sigmask進(jìn)行設(shè)置后,主進(jìn)程創(chuàng)建出來(lái)的線程將繼承主進(jìn)程的掩碼)
- pthread_sigmask - examine and change mask of blocked signals
- #include <signal.h>
- int pthread_sigmask(int
how, const sigset_t *set, sigset_t *oldset);
- Compile and link with -pthread.
- DESCRIPTION
- The pthread_sigmask() function is just like sigprocmask(2), with the difference that
its use
- in multithreaded programs is explicitly specified by POSIX.1-2001.
- Other differences are noted in this page.
- For a description of the arguments and operation of this function, see sigprocmask(2).
- RETURN VALUE
- On success, pthread_sigmask() returns 0; on error, it returns an error number.
- NOTES
- A new thread inherits a copy of its creator's signal mask.
- (from man sigprocmask: )
- The behavior of the call is dependent on the value of how, as follows.
- SIG_BLOCK
- The set of blocked signals is the
union of the current set and the set argument.
- SIG_UNBLOCK
- The signals in set are removed from the current set of blocked signals. It is permissible
- to attempt to unblock a signal which is not blocked.
- SIG_SETMASK
- The set of blocked signals is
set to the argument set.
- If oldset is non-NULL, the previous value of the signal mask is stored in
oldset.
- If set is NULL, then the signal mask is unchanged (i.e.,
how is ignored), but the current
- value of the signal mask is nevertheless returned in
oldset (if it is not NULL).
4. pthread_kill函數(shù):
在多線程程序中,一個(gè)線程可以使用pthread_kill對(duì)同一個(gè)進(jìn)程中指定的線程(包括自己)發(fā)送信號(hào)。注意在多線程中
一般不使用kill函數(shù)發(fā)送信號(hào),因?yàn)閗ill是對(duì)進(jìn)程發(fā)送信號(hào),結(jié)果是:正在運(yùn)行的線程會(huì)處理該信號(hào),如果該線程沒(méi)有
注冊(cè)信號(hào)處理函數(shù),那么會(huì)導(dǎo)致整個(gè)進(jìn)程退出。
- #include <signal.h>
- int pthread_kill(pthread_t
thread, int sig);
- Compile and link with -pthread.
- DESCRIPTION
- The pthread_kill() function sends the signal
sig to thread, another thread in the same
- process as the caller. The signal is asynchronously directed to thread.
- If sig is 0, then no signal is sent, but error checking is still performed; this can be
- used to check for the existence of a thread ID.
- RETURN VALUE
- On success, pthread_kill() returns 0; on error, it returns an error number, and no signal
- is sent.
- ERRORS
- ESRCH No thread with the ID thread could be found.
- EINVAL An invalid signal was specified.
5. 記?。?/span>調(diào)用sigwait同步等待的信號(hào)必須在調(diào)用線程中被屏蔽,并且通常應(yīng)該在所有的線程中被屏蔽(這樣可以保證信號(hào)絕不會(huì)被送到除了調(diào)用sigwait的任何其它線程),這是通過(guò)利用信號(hào)掩碼的繼承關(guān)系來(lái)達(dá)到的。
(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)
- #include <pthread.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <signal.h>
- #include <errno.h>
- /* Simple
error handling functions
*/
- #define handle_error_en(en, msg)
\
- do { errno
= en; perror(msg);
exit(EXIT_FAILURE);
} while
(0)
- static void *
- {
- sigset_t *set
= (sigset_t
*) arg;
- int s, sig;
- for (;;)
{
- s = sigwait(set,
&sig);
- if
(s != 0)
- handle_error_en(s,
"sigwait");
- printf("Signal handling thread got signal %d\n", sig);
- }
- }
- int
- main(int argc, char
*argv[])
- {
- pthread_t thread;
- sigset_t set;
- int s;
- /*
- Block SIGINT; other threads created by main() will inherit
- a copy of the signal mask.
- */
- sigemptyset(&set);
- sigaddset(&set, SIGQUIT);
- sigaddset(&set, SIGUSR1);
- s = pthread_sigmask(SIG_BLOCK,
&set,
NULL);
- if (s
!= 0)
- handle_error_en(s,
"pthread_sigmask");
- s = pthread_create(&thread,
NULL,
&sig_thread,
(void *)
&set);
- if (s
!= 0)
- handle_error_en(s,
"pthread_create");
- /*
- Main thread carries on
to create other threads and/or
do
- other work
- */
- pause();
/* Dummy pause so we can test program
*/
- return 0;
- }
編譯運(yùn)行情況:
- digdeep@ubuntu:~/pthread/learnthread$ gcc
-Wall -pthread
-o pthread_sigmask pthread_sigmask.c
- digdeep@ubuntu:~/pthread/learnthread$
./pthread_sigmask
&
- [1] 4170
- digdeep@ubuntu:~/pthread/learnthread$ kill
-QUIT %1
- digdeep@ubuntu:~/pthread/learnthread$ Signal handling thread got signal 3
- digdeep@ubuntu:~/pthread/learnthread$ kill
-USR1 %1
- digdeep@ubuntu:~/pthread/learnthread$ Signal handling thread got signal 10
- digdeep@ubuntu:~/pthread/learnthread$ kill
-TERM %1
- digdeep@ubuntu:~/pthread/learnthread$
- [1]+ Terminated
./pthread_sigmask
- digdeep@ubuntu:~/pthread/learnthread$
這個(gè)例子演示了:通過(guò)在主線程中阻塞一些信號(hào),其它的線程會(huì)繼承信號(hào)掩碼,然后專(zhuān)門(mén)用一個(gè)線程使用sigwait函數(shù)來(lái)同步的處理信號(hào),使其它的線程不受到信號(hào)的影響。
|