多執行緒中的訊號機制--sigwait 函式
阿新 • • 發佈:2018-11-13
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!
在Linux的多執行緒中使用訊號機制,與在程序中使用訊號機制有著根本的區別,可以說是完全不同。在程序環境中,對訊號的處理是,先註冊訊號處理函式,當訊號非同步發生時,呼叫處理函式來處理訊號。它完全是非同步 的(我們完全不知到訊號會在程序的那個執行點到來!)。然而訊號處理函式的實現,有著許多的限制;比如有一些函式不能在訊號處理函式中呼叫;再比如一些函式read、recv等呼叫時會被非同步的訊號給中斷(interrupt),因此我們必須對在這些函式在呼叫時因為訊號而中斷的情況進行處理(判斷函式返回時 enno 是否等於 EINTR)。
但是在多執行緒中處理訊號的原則卻完全不同,它的基本原則是:將對訊號的非同步處理,轉換成同步處理,也就是說用一個執行緒專門的來“同步等待”訊號的到來,而其它的執行緒可以完全不被該訊號中斷/打斷(interrupt)。這樣就在相當程度上簡化了在多執行緒環境中對訊號的處理。而且可以保證其它的執行緒不受訊號的影響。這樣我們對訊號就可以完全預測
1. sigwait函式:
- 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 insig.
- 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.
- pthread_sigmask - examine and change mask of blocked signals
- #include <signal.h>
- int pthread_sigmask(inthow, 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 thatits 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 inoldset.
- 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 inoldset (if it is not NULL).
- #include <signal.h>
- int pthread_kill(pthread_tthread, intsig);
- 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.
- #include <pthread.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <signal.h>
- #include <errno.h>
- /* Simpleerror handling functions*/
- #define handle_error_en(en, msg)\
- do { errno= en; perror(msg);exit(EXIT_FAILURE);}while(0)
- static void *
- sig_thread(void*arg)
- {
- 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/ordo
- other work
- */
- pause();/* Dummy pause so we can test program*/
- return 0;
- }
- [email protected]:~/pthread/learnthread$ gcc-Wall-pthread-o pthread_sigmask pthread_sigmask.c
- [email protected]:~/pthread/learnthread$./pthread_sigmask&
- [1] 4170
- [email protected]:~/pthread/learnthread$ kill-QUIT%1
- [email protected]:~/pthread/learnthread$ Signal handling thread got signal 3
- [email protected]u:~/pthread/learnthread$ kill-USR1%1
- [email protected]:~/pthread/learnthread$ Signal handling thread got signal 10
- [email protected]:~/pthread/learnthread$ kill-TERM%1
- [email protected]:~/pthread/learnthread$
- [1]+ Terminated./pthread_sigmask
- [email protected]:~/pthread/learnthread$
#include <pthread.h>#include <stdio.h>#include <sys/signal.h>#define NUMTHREADS 3void sighand(int signo);void *threadfunc(void *parm){ pthread_t tid = pthread_self(); int rc; printf("Thread %u entered\n", tid); rc = sleep(3); printf("Thread %u did not get expected results! rc=%d\n", tid, rc); return NULL;}void *threadmasked(void *parm){ pthread_t tid = pthread_self(); sigset_t mask; int rc; printf("Masked thread %lu entered\n", tid); sigfillset(&mask); /* Mask all allowed signals */// sigemptyset(&mask); rc = pthread_sigmask(SIG_BLOCK, &mask, NULL); if (rc != 0) { printf("%d, %s\n", rc, strerror(rc)); return NULL; } rc = sleep(1); if (rc != 0) { printf("Masked thread %lu did not get expected results! ""rc=%d \n",tid, rc); return NULL; }// sigwait(&mask,&rc); printf("Masked thread %lu completed masked work\n",tid); return NULL;}int main(int argc, char **argv){ int rc; int i; struct sigaction actions; pthread_t threads[NUMTHREADS]; pthread_t maskedthreads[NUMTHREADS]; printf("Enter Testcase - %s\n", argv[0]); printf("Set up the alarm handler for the process\n"); memset(&actions, 0, sizeof(actions)); sigemptyset(&actions.sa_mask); actions.sa_flags = 0; actions.sa_handler = sighand; rc = sigaction(SIGALRM,&actions,NULL); printf("Create masked and unmasked threads\n"); for(i=0; i<NUMTHREADS; ++i) { rc = pthread_create(&threads[i], NULL, threadfunc, NULL); if (rc != 0) { printf("%d, %s\n", rc, strerror(rc)); return -1; } rc = pthread_create(&maskedthreads[i], NULL, threadmasked, NULL); if (rc != 0) { printf("%d, %s\n", rc, strerror(rc)); return -1; } } sleep(5); printf("Send a signal to masked and unmasked threads\n"); for(i=0; i<NUMTHREADS; ++i) { rc = pthread_kill(threads[i], SIGALRM); rc = pthread_kill(maskedthreads[i], SIGALRM); } printf("Wait for masked and unmasked threads to complete\n"); for(i=0; i<NUMTHREADS; ++i) { rc = pthread_join(threads[i], NULL); rc = pthread_join(maskedthreads[i], NULL); } printf("Main completed\n"); return 0;}void sighand(int signo){ pthread_t tid = pthread_self(); printf("Thread %lu in signal handler\n",tid); return;}
(ps:由上面的幾篇文章可知,執行緒中的訊號處理機制和程序中的訊號處理機制是不同的,或者說是完全不同的,一般在多執行緒中使用訊號的,或單獨啟動一個執行緒類處理訊號,在主程序中傳送訊號,在主程序中使用了pthread_mask()函式來處理訊號遮蔽資訊,這個時候在主程序中使用kill,這個時候執行緒也是可以接受到訊號的原因是pthread_mask繼承了主程序的訊號遮蔽資訊,這個時候也是可以在使用pthread_kill給相應的執行緒傳送相應的訊號,但是在有的程式中,線上程中使用pthread_mask,這個使用就必須使用pthread_kill來發送訊號了;但是在程序中的訊號機制沒有這麼複雜,程序中只需要註冊一個函式,就靜靜的等待訊號處理。不過在程序中使用的方法也是可以線上程中使用的)