raise()、硬件異常如 SIGSEGV、pthread_kill())→ 發送給產生信號的那個線程。kill()、sigqueue())→ 發送給主線程(或未屏蔽該信號的任意線程,內核選擇)。OS: Fedora 11, Kernel 2.6.29, GCC 4.4.0
編譯: gcc -g -W -Wall -Wextra -o mytest main.c -lpthread
// 主線程註冊 SIGQUIT (Ctrl+\)
// 子線程註冊 SIGINT (Ctrl+C)
// 兩線程均 pause() 等待
// 結果:無論按 Ctrl+C 還是 Ctrl+\,處理函數均在主線程執行(TID=主線程ID)
外部信號(終端發送給進程組)由內核投遞到主線程(或未屏蔽該信號的線程)。
// 主線程註冊 SIGSEGV 處理器
// 子線程循環 sleep(2) 並故意 *p = 'a' 觸發 SIGSEGV
// 結果:SIGSEGV 處理器在子線程執行
硬件異常(SIGSEGV、SIGFPE、SIGILL、SIGBUS)同步產生於故障指令所在線程,精確投遞給該線程。
// 主線程註冊 SIGQUIT
// 子線程循環 raise(SIGQUIT)
// 結果:SIGQUIT 處理器在子線程執行
raise() 調用 pthread_kill(pthread_self(), sig),精確投遞給調用線程。
pthread_sigmask) 和待處理信號集。raise、pthread_kill)→ 直接放入目標線程私有集合,精確投遞。pthread_sigmask(SIG_BLOCK, &set, NULL))。sigwait() 同步等待信號,將異步信號轉為同步處理,避免信號處理函數的限制(只能調用 async-signal-safe 函數)。sigaction 設置 SA_SIGINFO 獲取 siginfo_t,可知 si_pid/si_uid 判斷信號來源。void *signal_thread(void *arg) {
sigset_t set;
sigfillset(&set);
pthread_sigmask(SIG_BLOCK, &set, NULL); // 繼承屏蔽集
for (;;) {
int sig;
sigwait(&set, &sig); // 同步等待
handle_signal(sig); // 安全上下文中處理
}
return NULL;
}
int main() {
sigset_t set;
sigfillset(&set);
pthread_sigmask(SIG_BLOCK, &set, NULL); // 主線程及後續線程繼承屏蔽
pthread_t tid;
pthread_create(&tid, NULL, signal_thread, NULL);
// 業務邏輯...
}