第二十四篇:可靠訊號機制

穆晨發表於2017-01-28

前言

       曾經的 UNIX 系統中,訊號的不可靠的。什麼是不可靠?就是訊號丟失唄。那什麼是訊號丟失?就是當系統正在處理某個事務的時候,如果收到了某個訊號,但它不能及時處理這個訊號,那麼只能忽略掉此訊號

       而在可靠訊號機制中,如果發生了上述情況,則要求系統處理完當前的事務後,還能夠找回丟失的那個訊號。也就是說,要具備本文即將講述的 - 訊號的阻塞功能。

訊號的阻塞

       系統在訊號發生後,會在程式表中設定一個標誌。在訊號發生到程式表中設定一個標誌的時間間隔之內,我們稱訊號是未決的。所謂訊號阻塞,就是指將訊號保持未決狀態,直到使用者將訊號解除阻塞,該訊號才被接收。

重要概念:訊號集

       訊號集是一種資料型別,它能夠表述系統內所有的訊號:類似點陣圖,某位為 1 表示該位對應的訊號存在(被遮蔽),反之不存在(未被遮蔽)。對此資料型別的操作需要使用下表所提供的函式來進行:

       

大致步驟

       1. 儲存當前訊號遮蔽集

       2. 定義新的訊號遮蔽集

       3. 使新的訊號遮蔽集生效

       4. 恢復原來的訊號遮蔽集

       這四個步驟,所涉及到的只有一個函式:sigprocmask 函式,該函式的詳細說明請參考相關文件。

程式碼實現

       如下示例程式首先執行上述的步驟 1 2 3( 遮蔽退出訊號 ),然後掛起 5 秒鐘,然後在此期間產生 3 次退出訊號,再執行上述步驟 4,最後再掛起 5 秒鐘:

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <signal.h>
 4 
 5 // 訊號處理函式( 此類函式都是無返回且形參為一個整數,該整數即為所接收到的訊號 )
 6 static void sig_quit (int);
 7 
 8 int main (void) {
 9     
10     // 定義訊號集
11     sigset_t newmask, oldmask, pendmask;
12 
13     // 註冊退出訊號處理函式
14     if (signal(SIGQUIT, sig_quit) == SIG_ERR) {
15         printf("註冊訊號處理函式失敗\n");
16         return 1;
17     }
18 
19     // 建立一個新的訊號遮蔽字
20     sigemptyset(&newmask);
21     sigaddset(&newmask, SIGQUIT);
22 
23     // 遮蔽退出訊號,並將原來的訊號遮蔽字儲存起來。
24     if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) {
25         printf("遮蔽退出訊號失敗\n");
26         return 2;
27     }
28 
29     printf("已遮蔽退出訊號\n");
30 
31     sleep(5);
32 
33     // 恢復原來的訊號遮蔽字
34     printf("\n接下來恢復原來的訊號遮蔽字\n");
35     if (sigprocmask(SIG_SETMASK, &oldmask, 0) < 0) {
36         printf("恢復訊號遮蔽字失敗\n");
37         return 2;
38     }
39 
40     sleep(5);
41 
42     return 0;
43 }
44 
45 static void sig_quit (int signo)
46 {
47     printf("捕捉到退出訊號\n");
48 
49     // 將對退出訊號的處理設定為關閉程式
50     if (signal(SIGQUIT, SIG_DFL) == SIG_ERR) {
51         printf("設定退出訊號處理函式失敗\n");
52     }
53 }

執行測試

       

       第一次睡眠時,我發出了三次退出訊號,結果只接收並處理了一次( 假如接收了兩次,則第二次就會結束掉程式了。)。

       當恢復到之前的訊號遮蔽字以後,我再發出退出訊號,程式立刻就關閉了。

小結

       1. 可靠訊號可靠之處在於可以使訊號阻塞,到合適的時候再解除阻塞,接收訊號。

       2. 使用 sigaction 函式實現可靠訊號更加方便。

相關文章