# 信號,第 2 部分:待處理的信號和信號掩碼
> 原文:<https://github.com/angrave/SystemProgramming/wiki/Signals%2C-Part-2%3A-Pending-Signals-and-Signal-Masks>
## 信號深度
## 如何了解有關信號的更多信息?
linux 手冊頁討論了第 2 節中的信號系統調用。第 7 節中還有一篇較長的文章(盡管不在 OSX / BSD 中):
```
man -s7 signal
```
## 信號術語
* 生成 - 通過 kill 系統調用在內核中創建信號。
* 待定 - 尚未交付但很快將交付
* 已阻止 - 未傳送,因為沒有信號處理可以傳送信號
* 交付 - 交付過程,正在采取所述行動
* 抓住 - 當進程停止信號來摧毀它并用它做其他事情時
## 什么是進程的信號處理?
對于每個過程,每個信號都有一個配置,這意味著當信號傳遞給過程時會發生什么動作。例如,默認處置 SIGINT 是終止它。信號處理可以通過調用 signal()來改變(這是簡單但不可移植的,因為它在不同的 POSIX 架構上的實現有細微的變化,也不推薦用于多線程程序)或`sigaction`(稍后討論)。您可以將過程對所有可能信號的處置想象為函數指針條目表(每個可能的信號一個)。
信號的默認處置可以是忽略信號,停止進程,繼續停止進程,終止進程,或終止進程并轉儲'核心'文件。請注意,核心文件是可以使用調試器檢查的進程內存狀態的表示。
## 多個信號可以排隊嗎?
否 - 但是可能有信號處于掛起狀態。如果信號處于待處理狀態,則表示尚未交付給該進程。信號待決的最常見原因是進程(或線程)當前阻止了該特定信號。
如果是特定信號,例如 SIGINT 正在等待,因此無法再次排隊相同的信號。
可能在待處理狀態下具有多個不同類型的信號。例如,SIGINT 和 SIGTERM 信號可能正在等待(即尚未傳送到目標進程)
## 如何阻止信號?
通過設置過程信號掩碼,或者在編寫多線程程序時,可以阻止信號(意味著它們將保持在掛起狀態),線程信號掩碼。
## 線程/子項中的處置
## 創建新線程時會發生什么?
新線程繼承了調用線程掩碼的副本
```c
pthread_sigmask( ... ); // set my mask to block delivery of some signals
pthread_create( ... ); // new thread will start with a copy of the same mask
```
## 分叉時會發生什么?
子進程繼承父進程信號處理的副本。換句話說,如果您在分叉之前安裝了 SIGINT 處理程序,那么如果將 SIGINT 傳遞給子進程,子進程也將調用處理程序。
注意孩子的待處理信號是 _ 而不是 _ 在分叉期間繼承的。
## exec 期間會發生什么?
信號掩碼和信號配置都轉移到執行程序。 [https://www.gnu.org/software/libc/manual/html_node/Executing-a-File.html#Executing-a-File](Source) 也會保留待處理信號。信號處理程序被重置,因為原始處理程序代碼與舊進程一起消失。
## 叉期間會發生什么?
子進程繼承父進程的信號處理副本和父進程信號掩碼的副本。
例如,如果在父母中阻止`SIGINT`,它也將在孩子中被阻止。例如,如果父級為 SIG-INT 安裝了處理程序(回調函數),則子級也將執行相同的行為。
然而,待定信號不是由孩子繼承的。
## 如何在單線程程序中阻止信號?
使用`sigprocmask`!使用 sigprocmask,您可以設置新掩碼,將要阻止的新信號添加到進程掩碼,以及取消阻止當前阻塞的信號。您還可以通過傳入 oldset 的非 null 值來確定現有掩碼(并在以后使用它)。
```
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);`
```
從 sigprocmask 的 Linux 手冊頁,
```
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.
```
sigset 類型表現為位圖,除了使用函數而不是使用&amp;顯式設置和取消設置位。和|。
在修改一位之前忘記初始化信號集是一個常見的錯誤。例如,
```c
sigset_t set, oldset;
sigaddset(&set, SIGINT); // Ooops!
sigprocmask(SIG_SETMASK, &set, &oldset)
```
正確的代碼將該集初始化為全部打開或全部關閉。例如,
```c
sigfillset(&set); // all signals
sigprocmask(SIG_SETMASK, &set, NULL); // Block all the signals!
// (Actually SIGKILL or SIGSTOP cannot be blocked...)
sigemptyset(&set); // no signals
sigprocmask(SIG_SETMASK, &set, NULL); // set the mask to be empty again
```
## 如何在多線程程序中阻止信號?
多線程程序中的阻塞信號類似于單線程程序:
* 使用 pthread_sigmask 而不是 sigprocmask
* 阻止所有線程中的信號以防止其異步傳遞
確保信號在所有線程中被阻止的最簡單方法是在創建新線程之前在主線程中設置信號掩碼
```c
sigemptyset(&set);
sigaddset(&set, SIGQUIT);
sigaddset(&set, SIGINT);
pthread_sigmask(SIG_BLOCK, &set, NULL);
// this thread and the new thread will block SIGQUIT and SIGINT
pthread_create(&thread_id, NULL, myfunc, funcparam);
```
正如我們在 sigprocmask 中看到的那樣,pthread_sigmask 包含一個'how'參數,用于定義如何使用信號集:
```c
pthread_sigmask(SIG_SETMASK, &set, NULL) - replace the thread's mask with given signal set
pthread_sigmask(SIG_BLOCK, &set, NULL) - add the signal set to the thread's mask
pthread_sigmask(SIG_UNBLOCK, &set, NULL) - remove the signal set from the thread's mask
```
## 如何在多線程程序中提供待處理信號?
信號被傳送到任何未阻塞該信號的信號線程。
如果兩個或多個線程可以接收信號,那么哪個線程將被中斷是任意的!
- UIUC CS241 系統編程中文講義
- 0. 簡介
- #Informal 詞匯表
- #Piazza:何時以及如何尋求幫助
- 編程技巧,第 1 部分
- 系統編程短篇小說和歌曲
- 1.學習 C
- C 編程,第 1 部分:簡介
- C 編程,第 2 部分:文本輸入和輸出
- C 編程,第 3 部分:常見問題
- C 編程,第 4 部分:字符串和結構
- C 編程,第 5 部分:調試
- C 編程,復習題
- 2.進程
- 進程,第 1 部分:簡介
- 分叉,第 1 部分:簡介
- 分叉,第 2 部分:Fork,Exec,等等
- 進程控制,第 1 部分:使用信號等待宏
- 進程復習題
- 3.內存和分配器
- 內存,第 1 部分:堆內存簡介
- 內存,第 2 部分:實現內存分配器
- 內存,第 3 部分:粉碎堆棧示例
- 內存復習題
- 4.介紹 Pthreads
- Pthreads,第 1 部分:簡介
- Pthreads,第 2 部分:實踐中的用法
- Pthreads,第 3 部分:并行問題(獎金)
- Pthread 復習題
- 5.同步
- 同步,第 1 部分:互斥鎖
- 同步,第 2 部分:計算信號量
- 同步,第 3 部分:使用互斥鎖和信號量
- 同步,第 4 部分:臨界區問題
- 同步,第 5 部分:條件變量
- 同步,第 6 部分:實現障礙
- 同步,第 7 部分:讀者編寫器問題
- 同步,第 8 部分:環形緩沖區示例
- 同步復習題
- 6.死鎖
- 死鎖,第 1 部分:資源分配圖
- 死鎖,第 2 部分:死鎖條件
- 死鎖,第 3 部分:餐飲哲學家
- 死鎖復習題
- 7.進程間通信&amp;調度
- 虛擬內存,第 1 部分:虛擬內存簡介
- 管道,第 1 部分:管道介紹
- 管道,第 2 部分:管道編程秘密
- 文件,第 1 部分:使用文件
- 調度,第 1 部分:調度過程
- 調度,第 2 部分:調度過程:算法
- IPC 復習題
- 8.網絡
- POSIX,第 1 部分:錯誤處理
- 網絡,第 1 部分:簡介
- 網絡,第 2 部分:使用 getaddrinfo
- 網絡,第 3 部分:構建一個簡單的 TCP 客戶端
- 網絡,第 4 部分:構建一個簡單的 TCP 服務器
- 網絡,第 5 部分:關閉端口,重用端口和其他技巧
- 網絡,第 6 部分:創建 UDP 服務器
- 網絡,第 7 部分:非阻塞 I O,select()和 epoll
- RPC,第 1 部分:遠程過程調用簡介
- 網絡復習題
- 9.文件系統
- 文件系統,第 1 部分:簡介
- 文件系統,第 2 部分:文件是 inode(其他一切只是數據...)
- 文件系統,第 3 部分:權限
- 文件系統,第 4 部分:使用目錄
- 文件系統,第 5 部分:虛擬文件系統
- 文件系統,第 6 部分:內存映射文件和共享內存
- 文件系統,第 7 部分:可擴展且可靠的文件系統
- 文件系統,第 8 部分:從 Android 設備中刪除預裝的惡意軟件
- 文件系統,第 9 部分:磁盤塊示例
- 文件系統復習題
- 10.信號
- 過程控制,第 1 部分:使用信號等待宏
- 信號,第 2 部分:待處理的信號和信號掩碼
- 信號,第 3 部分:提高信號
- 信號,第 4 部分:信號
- 信號復習題
- 考試練習題
- 考試主題
- C 編程:復習題
- 多線程編程:復習題
- 同步概念:復習題
- 記憶:復習題
- 管道:復習題
- 文件系統:復習題
- 網絡:復習題
- 信號:復習題
- 系統編程笑話