一,訊號集及相關操作函數
訊號集被定義為一種資料類型:
typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t
訊號集用來描述訊號的集合,每個訊號佔用一位(64位)。Linux所支援的所有訊號可以全部或部分的出現在訊號集中,主要與訊號阻塞相關函數配合使用。下面是為訊號集操作定義的相關函數:
#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum)
int sigdelset(sigset_t *set, int signum);
int sigismember(const sigset_t *set, int signum);
sigemptyset(sigset_t *set)初始化由set指定的訊號集,訊號集裡面的所有訊號被清空,相當於64為置0;
sigfillset(sigset_t *set)調用該函數後,set指向的訊號集中將包含linux支援的64種訊號,相當於64為都置1;
sigaddset(sigset_t *set, int signum)在set指向的訊號集中加入signum訊號,相當於將給定訊號所對應的位置1;
sigdelset(sigset_t *set, int signum)在set指向的訊號集中刪除signum訊號,相當於將給定訊號所對應的位置0;
sigismember(const sigset_t *set, int signum)判定訊號signum是否在set指向的訊號集中,相當於檢查給定訊號所對應的位是0還是1。
樣本程式:
#include <stdio.h><unistd.h><stdlib.h><signal.h><sys/types.h> print_sigset(sigset_t * main(&&&&&& print_sigset(sigset_t *(i = ; i < NSIG; ++(sigismember(
結果:
可以看到添加訊號的相應位置1.二,訊號阻塞與未決
man協助說明:
Signal mask and pending signals
A signal may be blocked, which means that it will not be delivered until it is later unblocked. Between the time when it is generated and when it is delivered a signal is said to be pending. Each thread in a process has an independent signal mask, which indicates the set of signals that the thread is currently blocking. A thread can manipulate its signal mask using pthread_sigmask(3). In a traditional single-threaded application, sigprocmask(2) can be used to manipulate the signal mask.
執行訊號的處理動作稱為訊號遞達(Delivery),訊號從產生到遞達之間的狀態,稱為訊號未決(Pending)。進程可以選擇阻塞(Block)某個訊號。被阻塞的訊號產生時將保持在未決狀態,直到進程解除對此訊號的阻塞,才執行遞達的動作。注意,阻塞和忽略是不同的,只要訊號被阻塞就不會遞達,而忽略是在遞達之後可選的一種處理動作。每個進程都有一個用來描述哪些訊號遞送到進程時將被阻塞的訊號集,該訊號集中的所有訊號在遞送到進程後都將被阻塞。
訊號在核心中的表示可以看作是這樣的:
看圖說話:
block集(阻塞集、屏蔽集):一個進程所要屏蔽的訊號,在對應要屏蔽的訊號位置1
pending集(未決訊號集):如果某個訊號在進程的阻塞集中,則也在未決集中對應位置1,表示該訊號不能被遞達,不會被處理
handler(訊號處理函數集):表示每個訊號所對應的訊號處理函數,當訊號不在未決集中時,將被調用
以下是與訊號阻塞及未決相關的函數操作:
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset));
int sigpending(sigset_t *set));
int sigsuspend(const sigset_t *mask));
sigprocmask()函數能夠根據參數how來實現對訊號集的操作,操作主要有三種:
- SIG_BLOCK 在進程當前阻塞訊號集中添加set指向訊號集中的訊號,相當於:mask=mask|set
- SIG_UNBLOCK 如果進程阻塞訊號集中包含set指向訊號集中的訊號,則解除對該訊號的阻塞,相當於:mask=mask|~set
- SIG_SETMASK 更新進程阻塞訊號集為set指向的訊號集,相當於mask=set
sigpending(sigset_t *set))獲得當前已遞送到進程,卻被阻塞的所有訊號,在set指向的訊號集中返回結果。
sigsuspend(const sigset_t *mask))用於在接收到某個訊號之前, 臨時用mask替換進程的訊號掩碼, 並暫停進程執行,直到收到訊號為止。
sigsuspend 返回後將恢複調用之前的訊號掩碼。訊號處理函數完成後,進程將繼續執行。該系統調用始終返回-1,並將errno設定為EINTR。
樣本程式:
#include <unistd.h><sys/stat.h><sys/wait.h><sys/types.h><fcntl.h><stdlib.h><stdio.h><errno.h><.h><signal.h> ERR_EXIT(m) \ ( handler( printsigset(sigset_t * (i=; i<NSIG; ++ (sigismember( main( argc, *&& (signal(SIGINT, handler) == (signal(SIGQUIT, handler) ==&bset, NULL); && handler( (sig == (sig ==&&&
結果:
說明:程式首先將SIGINT訊號加入進程阻塞集(屏蔽集)中,一開始並沒有發送SIGINT訊號,所以進程未決集中沒有處於未決態的訊號,當我們連續按下ctrl+c時,向進程發送SIGINT訊號,由於SIGINT訊號處於進程的阻塞集中,所以發送的SIGINT訊號不能遞達,也是就是處於未決狀態,所以當我列印未決集合時發現SIGINT所對應的位為1,現在我們按下ctrl+\,發送SIGQUIT訊號,由於此訊號並沒被進程阻塞,所以SIGQUIT訊號直接遞達,執行對應的處理函數,在該處理函數中解除進程對SIGINT訊號的阻塞,所以之前發送的SIGINT訊號遞達了,執行對應的處理函數,但由於SIGINT訊號是不可靠訊號,不支援排隊,所以最終只有一個訊號遞達。
#include <signal.h><stdio.h><stdlib.h><error.h><.h><unistd.h> MYSIGNAL SIGRTMIN+5 sig_handler( main( argc, **&&&= & (sig = ; sig < NSIG; sig++ (sigismember(&= (flag == &= & (sig = ; sig < NSIG; sig++ (sigismember(&= (flag ==
結果:
兩次執行結果不同:第一次連續發送兩次不可靠訊號,最後解除阻塞時,只有一個遞達,說明不可靠訊號不支援排隊。
第二次執行時,連續兩次發送可靠訊號,解除阻塞後,都遞達,說明可靠訊號支援排隊。
ok,這節就寫到這吧