1. 程式人生 > >Linux訊號 三 訊號傳送介面集合

Linux訊號 三 訊號傳送介面集合

訊號傳送介面包括raise,kill,killpg,tkill,tgkill,pthread_kill,sigqueue等。

1. raise()

/**
 * raise用於向程序自身傳送訊號
 * 成功返回0,失敗返回非0值,並置errno.
 * 只有訊號處理函式執行完畢之後,raise才能返回。
 *
 * 對於單執行緒的程式而言,相當於呼叫瞭如下語句:
 * kill(getpid(), sig);
 * 
 * 對於多執行緒的程式而言,相當於呼叫瞭如下語句: 
 * pthread_kill(pthread_self(), sig);
 */
#include <signal.h>
int raise(int sig);

 2. kill()

/**
 * kill函式用於傳送訊號,不僅可以向特定程序組傳送訊號,也可以向特定程序傳送訊號.
 * 根據引數pid的不同,分為如下幾種情況:
 * pid > 0, 傳送訊號給程序ID等於pid的程序。
 * pid = 0, 傳送訊號給呼叫程序所在的同一個程序組的每一個程序。
 * pid = -1, 有許可權向呼叫程序傳送訊號的所有程序傳送訊號,init程序和程序自身除外
 * pid < -1, 向程序組-pid傳送訊號。
 * sig = 0,檢測目標程序或目標程序組是否存在,如果返回-1並且errno為ESRCH表示目標
 * 或目標程序組不存在。
 *
 * 成功返回0,失敗返回-1,並置errno
 *
 */
#include <sys/types.h>
#include <signal.h>

int kill(pid_t pid, int sig);

3. killpg()

/**
 * 向程序組傳送訊號
 * pgrp = 0,向程序自身所在程序組傳送訊號。
 * pgrp <= 1,將引發未定義的行為。
 *
 * 成功返回0,失敗返回-1並置errno.
 *
 */
#include <signal.h>
int killpg(int pgrp, int sig);

4. tkill() & tgkill()

/*
 * 向執行緒傳送訊號
 * 
 * 這兩個都是核心提供的系統呼叫,glibc並沒有提供對這兩個系統呼叫的封裝,如果使用
 * 這兩個函式,需要採用syscall的方式:
 * ret = syscall(SYS_tkill, tid, sig);
 * ret = syscall(SYS_tgkill, tgid, sig);
 * 成功返回0,失敗返回-1並置errno
 *
 * tkill是一個過時的介面,並不推薦使用它來向執行緒傳送訊號。相比之下,tgkill介面更加
 * 安全。tgkill系統呼叫的第一個引數tgid,為執行緒中主執行緒的執行緒ID,或者稱為程序號。
 * 這個引數能夠起到保護作用,防止向錯誤的執行緒傳送訊號。程序ID或執行緒ID是由核心負責
 * 管理,程序或執行緒有自己的生命週期,使用tkill傳送訊號有可能執行緒已經退出,這時候會
 * 將訊號傳送到不相關的程序上,為了防止出現這種情況,核心引入了tgkill系統呼叫,
 * 含義是向執行緒組ID是tgid、執行緒ID為tid的執行緒傳送訊號,避免發錯訊號。
 * 這兩個函式是Linux特有的,存在一致性問題。
 *
 */
int tkill(int tid, int sig);
int tgkill(int tgid, int tid, int sig);

5. pthread_kill()

/**
 * 向同一個程序內的執行緒傳送訊號
 *
 * 成功返回0,失敗返回錯誤碼。
 * 如果sig = 0,將不傳送任何訊號。
 * 如果向一個已經退出的執行緒傳送訊號,將會引發未定義的行為。比如說段錯誤等。
 * 編譯的時候加上-pthread選項
 *
 */
#include <signal.h>
int pthread_kill(pthread_t thread, int sig);

6. sigqueue()

/**
 * 向程序ID等有pid的程序傳送訊號和資料
 * 成功返回0,失敗返回-1並置errno
 * 
 * 第三個引數為伴隨資料,可以向目標程序傳送一個整形資料或者指標,當目標程序註冊
 * 訊號處理函式使用了SA_SIGINFO標誌位的時候就可以接收到該資料
 *
 *     union sigval {
 *         int   sival_int;
 *         void *sival_ptr;
 *     };
 *
 * 傳送sig = 0的訊號可以用來檢測目標程序是否存在,返回錯誤碼為ESRCH
 *
 *
 *
*/

#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval value);

參考資料:

1. 《Linux環境程式設計,從應用到核心》高峰,李彬著

2. man signal : http://www.man7.org/linux/man-pages/man7/signal.7.html