# 信號,第 4 部分:信號
> 原文:<https://github.com/angrave/SystemProgramming/wiki/Signals%2C-Part-4%3A-Sigaction>
## 我如何以及為何使用`sigaction`?
您應該使用`sigaction`而不是`signal`,因為它具有更好的定義語義。 `signal`在不同的操作系統上做了不同的事情,**壞** `sigaction`更便攜,如果需要更好地為線程定義。
要改變過程的“信號處理” - 即當信號傳遞到您的過程時會發生什么 - 使用`sigaction`
您可以使用系統調用`sigaction`來設置信號的當前處理程序,或者讀取特定信號的當前信號處理程序。
```c
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
```
sigaction 結構包括兩個回調函數(我們只會查看'handler'版本),一個信號掩碼和一個 flags 字段 -
```c
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
};
```
## 如何將`signal`調用轉換為等效的`sigaction`調用?
假設您為警報信號安裝了信號處理程序,
```c
signal(SIGALRM, myhandler);
```
等效的`sigaction`代碼是:
```c
struct sigaction sa;
sa.sa_handler = myhandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGALRM, &sa, NULL)
```
但是,我們通常也可以設置掩碼和標志字段。掩碼是在信號處理程序執行期間使用的臨時信號掩碼。 SA_RESTART 標志將自動重啟一些(但不是全部)系統調用,否則這些調用將提前返回(帶有 EINTR 錯誤)。后者意味著我們可以稍微簡化代碼的其余部分,因為可能不再需要重啟循環。
```c
sigfillset(&sa.sa_mask);
sa.sa_flags = SA_RESTART; /* Restart functions if interrupted by handler */
```
## 我如何使用 sigwait?
Sigwait 可用于一次讀取一個待處理信號。 `sigwait`用于同??步等待信號,而不是在回調中處理它們。下面顯示了多線程程序中 sigwait 的典型用法。請注意,首先設置線程信號掩碼(并且將由新線程繼承)。這可以防止信號被 _ 傳遞 _,因此它們將保持掛起狀態,直到調用 sigwait。還要注意 sigwait 使用相同的 set sigset_t 變量 - 除了設置阻塞信號集之外,它被用作 sigwait 可以捕獲和返回的信號集。
編寫自定義信號處理線程(例如下面的示例)而不是回調函數的一個優點是,您現在可以使用更多的 C 庫和系統函數,否則這些函數無法在信號處理程序中安全使用,因為它們不是異步的信號安全。
基于`http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_sigmask.html`
```c
static sigset_t signal_mask; /* signals to block */
int main (int argc, char *argv[])
{
pthread_t sig_thr_id; /* signal handler thread ID */
sigemptyset (&signal_mask);
sigaddset (&signal_mask, SIGINT);
sigaddset (&signal_mask, SIGTERM);
pthread_sigmask (SIG_BLOCK, &signal_mask, NULL);
/* New threads will inherit this thread's mask */
pthread_create (&sig_thr_id, NULL, signal_thread, NULL);
/* APPLICATION CODE */
...
}
void *signal_thread (void *arg)
{
int sig_caught; /* signal caught */
/* Use same mask as the set of signals that we'd like to know about! */
sigwait(&signal_mask, &sig_caught);
switch (sig_caught)
{
case SIGINT: /* process SIGINT */
...
break;
case SIGTERM: /* process SIGTERM */
...
break;
default: /* should normally not happen */
fprintf (stderr, "\nUnexpected signal %d\n", sig_caught);
break;
}
}
```
- 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 編程:復習題
- 多線程編程:復習題
- 同步概念:復習題
- 記憶:復習題
- 管道:復習題
- 文件系統:復習題
- 網絡:復習題
- 信號:復習題
- 系統編程笑話