POSIX信號處理


        信號(signal)就是通知某個進程發生了某個事件,有時也稱為軟件中斷(software interrupt)。信號通常是異步發生的,也就是說進程預先不知道信號准確發生的時刻。

        信號可以:

                    由一個進程發送給另一個進程(或自身)。

                    由內核發給某個進程。

        每個信號都有一個與之關聯的處置(disposition),也稱為行為(action)。我們通過sigaction函數來設定一個信號的處置,並有三種選擇。

                   1. 我們提供一個函數,他將在特定信號發生的任何時刻被調用。

                   2. 我們可以發某個信號設置為SIG_IGN來忽略(ignore)它。SIGKILL和SIGSTOP這兩個信號不能被忽略。

                   3. 我們可以把某個信號的處置設定為SIG_DFL來啟用他的缺省(default)處理。(缺省處置通常是在收到信號后終止進程,有些信號可能會產生一個core image, 內存影像)

        signal函數

                     建立信號處理的POSIX方法就是調用sigaction函數,不過這個函數有點復雜,它需要接受一個結構參數;比較簡單的方法是調用signal函數,signal函數的第一個參數為信號名,第二個參數可以是一個指向函數的指針,也可以是一個常值,如:SIG_IGN,SIG_DFL。不過signal是早於POSIX出現的悠久函數,調用它時,不同的實現提供不同的信號語義以達成后向兼容,而POSIX則明確規定調用sigaction時的信號語義。為了方便,我們一般會定義一個自己的signal函數,在這個函數里邊調用sigaction函數,這樣就以所期望的POSIX語義提供了一個簡單的接口。下邊我們看來自《UNIX網絡編程》卷一的實現:

sigfunc* signal( int signal, sigfunc *func ) {

    struct sigaction act, oact;
    act.sa_handler = func;
    sigemptyset( &act.sa_mask );
    act.sa_flags = 0;
    if ( signo == SIGALRM ) {
#ifdef            SA_INTERRUPT
        act.sa_flags |= SA_INTERRUPT;    /* SunOS 4.x */
#endif
    } else {
#ifdef           SA_RESTART
        act.sa_flags |= SA_RESTART;    /* SVR4, 4.4BSD */
#endif
    }
    if ( sigaction(signo, &act, &oact) < 0 ) {
        return SIG_ERR;
    }
    return oac.sa_handler;

}

 

                      在上邊這段代碼中,sigfunc為一個函數指針,在由signal指定的信號發生的時候調用的處理函數;

                      sigemptyset( &act.sa_mask ); 設置處理函數的信號掩碼

                               POSIX允許我們指定這樣一組信號,他們在信號處理函數被調用時阻塞(這里的阻塞是指阻塞某個信號或某個信號集,防止它們在阻塞期間遞交;不同於系統調用的阻塞),任何阻塞的信號都不能遞交給進程。我們把sa_mask成員設置為空集,意味着在該信號處理函數運行期間,不阻塞額外的信號。POSIX保證被捕獲的信號在其信號處理函數運行期間總是阻塞的(其他的信號不能遞交給進程)。

                      “if ( signo == SIGALRM ) { "   if語句中設置SA_RESTART標志

                               SA_RESTART標志是可選的。如果設置,由相應信號中斷的系統調用將有內核自動重啟。如果被捕獲的信號不是SIGALRM且SA_RESTART有定義,我們就設置該標志,一些較早期的系統(如SunOS 4.x)缺省設置成自動重啟被中斷的系統調用,並定義了與SA_RESTART互補的SA_INTERRUPT標志,如果定義了該標志,我們就在被捕獲的信號是SIGALRM時設置它。假設一個進程正在進行accept系統調用,此時收到一個信號,如果在4.4BSD下,則內核會自動重啟被中斷的系統調用,accept不會返回錯誤;如果是在Solaris9下, 由於SA_RESTART標志並沒有設置,那么accept會返回一個EINTR錯誤(被中斷的系統調用)。

                       最后我們調用sigaction函數,並將相應信號舊的行為作為signal的返回值。

 

        符合POSIX的系統信號處理總結:

                1. 一旦安裝了信號處理函數,它便一直安裝者(較早期的系統是每執行一次就將其拆除)。

                2. 在一個信號處理函數運行期間,正被遞交的信號是阻塞的。

                3. 如果一個信號在被阻塞期間產生了一次或多次,那么該信號被解阻塞之后通常只遞交一次,也就是說Unix信號缺省是不排隊的。

                4. 利用sigprocmask函數選擇性地阻塞或解阻塞一組信號是可能的。這使得我們可以做到在一段臨界區代碼執行期間,防止捕獲某些信號,以此保護這段代碼。                     


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM