日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

12.8 线程和信号

發(fā)布時間:2023/11/30 编程问答 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 12.8 线程和信号 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.


在基于進程模型的信號處理已經(jīng)比較嗎麻煩了,引入線程后事情就更加復(fù)雜了。
每個線程擁有其自身的信號掩碼,但是信號處理函數(shù)是被進程內(nèi)的所有線程共享的,作為一個推論,獨立的線程能夠阻塞信號,但是如果一個線程修改與給定信號的處理動作的時候,所有的線程都會共享這一修改。也就是說,如果一個線程選擇忽略一個給定信號,其他的線程可能會通過恢復(fù)默認呢處理或者是安裝信號處理函數(shù)的方式撤銷線程所做的忽略選擇。
信號會只會被發(fā)送到進程內(nèi)的一個線程。如果信號與硬件錯誤相關(guān),那么信號通常被發(fā)送到造成時間發(fā)生的線程,其他信號,將被發(fā)送到任意一個線程。
在10.12節(jié)中,我們介紹了進程可以使用函數(shù)sigprocmask函數(shù)來阻塞信號的發(fā)送,然而,sigprocmask函數(shù)在多線程進程中的行為是未定義的,線程必須使用函數(shù)pthread_sigmask予以代替。

  • #include <signal.h>
  • int pthread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);
  • Returns: 0 if OK, error number on failure.
  • 函數(shù)pthread_sigmask與函數(shù)sigprocmask相似,但是pthread_sigmask函數(shù)在失敗的時候返回一個錯誤碼,而函數(shù)sigprocmask在失敗的時候返回-1并且設(shè)置errno變量。
    參數(shù)how可以取三個不同的數(shù)值:
    * SIG_BLOCK添加信號集到線程的信號掩碼中;
    * SIG_SETMASK使用信號集替換線程的信號掩碼;
    * SIG_UNBLOCK從線程的信號掩碼中移除信號集;
    如果oset參數(shù)不是null,那么線程的前一個信號掩碼將被存儲到oset指針指向的內(nèi)存中。線程可以通過設(shè)置set參數(shù)為null的情況下獲取其當(dāng)前的信號掩碼,著這種情況下,how參數(shù)將被忽略。

    線程可以調(diào)用函數(shù)sigwait來等待一個或者多個信號的出現(xiàn);

  • #include <signal.h>
  • int sigwait(const sigset_t *restrict set, int *restrict signop);
  • Returns: 0 if OK, error number on failure.
  • 參數(shù)set指定了線程正在等待信號的集合,參數(shù)signop指針指向的內(nèi)存將會存儲被發(fā)送的信號數(shù)量。
    如果在sigwait函數(shù)被調(diào)用的時候,如果set中的一個信號處于掛起狀態(tài),那么函數(shù)sigwait就不會阻塞,而是直接返回,在返回之前,sigwait函數(shù)將會將從進程掛起的信號集中移除等到的信號。如果實現(xiàn)支持信號排隊,并且一個信號的多個實例處于掛起狀態(tài),函數(shù)sigwait僅僅移除其中一個實例,其他實例仍然處于排隊狀態(tài)。
    為了避免錯誤的行為,線程在調(diào)用函數(shù)sigwait之前必須先阻塞這些等待的信號。函數(shù)sigwait將會自動解除對應(yīng)信號的阻塞,并且一直等待知道其中一個信號被發(fā)送,在返回之前,sigwait將會恢復(fù)線程的信號掩碼,如果函數(shù)sigwait被調(diào)用的時候,對應(yīng)的信號沒有被阻塞,那么在完成函數(shù)sigwait之前會出現(xiàn)一個多于的時間窗口,在這個時間窗口內(nèi),信號可能被發(fā)送到了線程。
    使用函數(shù)sigwait的一個好處就是可以簡化信號處理函數(shù)的設(shè)計,因為它允許我們將異步信號處理當(dāng)作是同步信號來看待,我們可以通過將指定信號添加到線程的信號掩碼中,從而防止信號中斷線程的執(zhí)行,然后專門指定一個線程來處理信號,這些指定的線程在調(diào)用函數(shù)的時候不需要再考慮那些函數(shù)是信號處理安全的,因為在信號處理函數(shù)被調(diào)用的時候,線程處于正常的線程環(huán)境,而不是像傳統(tǒng)情況那樣:信號處理函數(shù)能夠中斷線程的正常執(zhí)行。
    如果多個線程由于調(diào)用了函數(shù)sigwait而阻塞在了同一個信號上,那么當(dāng)信號被發(fā)送的時候,僅僅只有一個線程將會返回,如果一個信號被捕獲,并且存在一個線程調(diào)用函數(shù)sigwait等待這一信號,如何發(fā)送信號是交給實現(xiàn)了決定的,實現(xiàn)可以允許sigwait返回或者是調(diào)用信號處理函數(shù),但是不能同時執(zhí)行這兩個動作。
    為了發(fā)送一個信號給進程,我們可以調(diào)用函數(shù)kill,為了發(fā)送一個信號給一個線程,我們可以調(diào)用函數(shù)pthread_kill;

  • #include <signal.h>
  • int pthread_kill(pthread_t thread, int signl);
  • Returns: 0 if ok, error number on failure.
  • 我們可以傳遞給參數(shù)signo數(shù)值0,用于檢測指定線程是否存在。如果一個信號的默認處理方式是終止進程,那么向一個線程發(fā)送這個信號也會終止掉整個進程。
    注意alarm timers是進程資源,所有的線程都會共享相同的alarms集合,因此,對于一個進程中的多個線程,不可能做到使用alarm timers而不發(fā)生沖突。

    Example

    在圖10.23中,我們等待信號處理函數(shù)設(shè)置一個標志,用于表示主程序可以退出了。在這個程序中,可以運行的程序流僅僅只有主線程以及信號處理函數(shù),所以阻塞信號對于避免丟失標志的改變是有效的。使用多線程以后,我們需要使用互斥鎖來保護標志,正如在圖12.16中程序所示。

  • #include "apue.h"
  • #include <pthread.h>
  • int quitflag; /* set nonzero by thread */
  • sigset_t mask;
  • pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
  • pthread_cond_t waitloc = PTHREAD_COND_INITIALIZER;
  • void *thr_fn(void *arg)
  • {
  • int err, signo;
  • for(;;)
  • {
  • err = sigwait(&mask, &signo);
  • if(err != 0)
  • err_exit(err, "sigwait failed");
  • switch(signo)
  • {
  • case SIGINT:
  • printf("\ninterrupt\n");
  • break;
  • case SIGQUIT:
  • pthread_mutex_lock(&lock);
  • quitflag = 1;
  • pthread_mutex_unlock(&lock);
  • pthread_cond_signal(&waitloc);
  • return (0);
  • default:
  • printf("unexpected signal %d\n", signo);
  • exit(1);
  • }
  • }
  • }
  • int main(void)
  • {
  • int err;
  • sigset_t oldmask;
  • pthread_t tid;
  • sigemptyset(&mask);
  • sigaddset(&mask, SIGINT);
  • sigaddset(&mask, SIGQUIT);
  • if((err = pthread_sigmask(SIG_BLOCK, &mask, &oldmask)) != 0)
  • err_exit(err, "SIG_BLOCK error");
  • err = pthread_create(&tid, NULL, thr_fn, 0);
  • if(err != 0)
  • {
  • err_exit(err, "can;t create thread");
  • }
  • pthread_mutex_lock(&lock);
  • while(quitflag == 0)
  • pthread_cond_wait(&waitloc, &lock);
  • pthread_mutex_unlock(&lock);
  • /*SIGQIUT has been caught and is now blocked; do whatever */
  • quitflag = 0;
  • /*reset signal mask which unblocks ISGQUIT */
  • if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
  • err_sys("SIG_SETMASK error");
  • exit(0);
  • }
  • 圖12.16 同步信號處理
    信號處理函數(shù)不再會中斷主線程,我們使用一個專門的線程來處理信號,我們可以在互斥鎖的保護下修改quitflag,so that the main thread of control can’t miss the wake-up call made when we call pthread_cond_signal.我們在主線程中使用同一互斥鎖來檢查標記的值,并在我們等待條件的時候自動釋放鎖。
    注意同時阻塞了信號SIGINT以及SIGQUIT信號,當(dāng)我們創(chuàng)建線程來處理信號的時候,線程繼承了當(dāng)前的信號掩碼,因為sigwait并不會阻塞信號,因此只有一個線程可以接受信號,這樣可以使得我們在編寫主線程的時候不用考慮這些中斷信號的干擾。
    程序運行情況如下入所示:

  • yuekunhu@debian:~/APUE/chapter12$ ./12_16.exe
  • ^C
  • interrupt
  • ^C
  • interrupt
  • ^C
  • interrupt
  • ^\yuekunhu@debian:~/APUE/chapter12$


  • 來自為知筆記(Wiz)

    轉(zhuǎn)載于:https://www.cnblogs.com/U201013687/p/5635947.html

    總結(jié)

    以上是生活随笔為你收集整理的12.8 线程和信号的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。