信号集操作函数,信号未决、阻塞、递达
轉(zhuǎn)載:信號(hào)集操作函數(shù),信號(hào)阻塞與未決
一,信號(hào)集及相關(guān)操作函數(shù)
信號(hào)集被定義為一種數(shù)據(jù)類型:
typedef struct {
?????????????????????? unsigned long sig[_NSIG_WORDS];
}?sigset_t
信號(hào)集用來(lái)描述信號(hào)的集合,每個(gè)信號(hào)占用一位(64位)。Linux所支持的所有信號(hào)可以全部或部分的出現(xiàn)在信號(hào)集中,主要與信號(hào)阻塞相關(guān)函數(shù)配合使用。下面是為信號(hào)集操作定義的相關(guān)函數(shù):
#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指定的信號(hào)集,信號(hào)集里面的所有信號(hào)被清空,相當(dāng)于64為置0;
sigfillset(sigset_t *set)調(diào)用該函數(shù)后,set指向的信號(hào)集中將包含linux支持的64種信號(hào),相當(dāng)于64為都置1;
sigaddset(sigset_t *set, int signum)在set指向的信號(hào)集中加入signum信號(hào),相當(dāng)于將給定信號(hào)所對(duì)應(yīng)的位置1;
sigdelset(sigset_t *set, int signum)在set指向的信號(hào)集中刪除signum信號(hào),相當(dāng)于將給定信號(hào)所對(duì)應(yīng)的位置0;
sigismember(const sigset_t *set, int signum)判定信號(hào)signum是否在set指向的信號(hào)集中,相當(dāng)于檢查給定信號(hào)所對(duì)應(yīng)的位是0還是1。
示例程序:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <signal.h> #include <sys/types.h> void print_sigset(sigset_t *set); int main(void) {sigset_t myset;sigemptyset(&myset);sigaddset(&myset,SIGINT);sigaddset(&myset,SIGQUIT);sigaddset(&myset,SIGUSR1);sigaddset(&myset,SIGRTMIN);print_sigset(&myset);return 0;} void print_sigset(sigset_t *set) {int i;for(i = 1; i < NSIG; ++i){if(sigismember(set,i))printf("1");elseprintf("0");}putchar('\n'); }結(jié)果:
可以看到添加信號(hào)的相應(yīng)位置1.
二,信號(hào)阻塞與未決
man幫助說(shuō)明:
Signal mask and pending signals
A signal may be blocked, which means that it will not be delivereduntil it is later unblocked. Between the time when it is generatedand when it is delivered a signal is said to be pending. Each thread in a process has an independent signal mask, whichindicates the set of signals that the thread is currently blocking.A thread can manipulate its signal mask using pthread_sigmask(3). Ina traditional single-threaded application, sigprocmask(2) can be usedto manipulate the signal mask. 執(zhí)行信號(hào)的處理動(dòng)作稱為信號(hào)遞達(dá)(Delivery),信號(hào)從產(chǎn)生到遞達(dá)之間的狀態(tài),稱為信號(hào)未決(Pending)。進(jìn)程可以選擇阻塞(Block)某個(gè)信號(hào)。被阻塞的信號(hào)產(chǎn)生時(shí)將保持在未決狀態(tài),直到進(jìn)程解除對(duì)此信號(hào)的阻塞,才執(zhí)行遞達(dá)的動(dòng)作。注意,阻塞和忽略是不同的,只要信號(hào)被阻塞就不會(huì)遞達(dá),而忽略是在遞達(dá)之后可選的一種處理動(dòng)作。每個(gè)進(jìn)程都有一個(gè)用來(lái)描述哪些信號(hào)遞送到進(jìn)程時(shí)將被阻塞的信號(hào)集,該信號(hào)集中的所有信號(hào)在遞送到進(jìn)程后都將被阻塞。 信號(hào)在內(nèi)核中的表示可以看作是這樣的: 看圖說(shuō)話: block集(阻塞集、屏蔽集):一個(gè)進(jìn)程所要屏蔽的信號(hào),在對(duì)應(yīng)要屏蔽的信號(hào)位置1 pending集(未決信號(hào)集):如果某個(gè)信號(hào)在進(jìn)程的阻塞集中,則也在未決集中對(duì)應(yīng)位置1,表示該信號(hào)不能被遞達(dá),不會(huì)被處理 handler(信號(hào)處理函數(shù)集):表示每個(gè)信號(hào)所對(duì)應(yīng)的信號(hào)處理函數(shù),當(dāng)信號(hào)不在未決集中時(shí),將被調(diào)用 ? 以下是與信號(hào)阻塞及未決相關(guān)的函數(shù)操作:#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()函數(shù)能夠根據(jù)參數(shù)how來(lái)實(shí)現(xiàn)對(duì)信號(hào)集的操作,操作主要有三種:
- SIG_BLOCK 在進(jìn)程當(dāng)前阻塞信號(hào)集中添加set指向信號(hào)集中的信號(hào),相當(dāng)于:mask=mask|set
- SIG_UNBLOCK 如果進(jìn)程阻塞信號(hào)集中包含set指向信號(hào)集中的信號(hào),則解除對(duì)該信號(hào)的阻塞,相當(dāng)于:mask=mask|~set
- SIG_SETMASK 更新進(jìn)程阻塞信號(hào)集為set指向的信號(hào)集,相當(dāng)于mask=set
sigpending(sigset_t *set))獲得當(dāng)前已遞送到進(jìn)程,卻被阻塞的所有信號(hào),在set指向的信號(hào)集中返回結(jié)果。
sigsuspend(const sigset_t *mask))用于在接收到某個(gè)信號(hào)之前, 臨時(shí)用mask替換進(jìn)程的信號(hào)掩碼, 并暫停進(jìn)程執(zhí)行,直到收到信號(hào)為止。
sigsuspend 返回后將恢復(fù)調(diào)用之前的信號(hào)掩碼。信號(hào)處理函數(shù)完成后,進(jìn)程將繼續(xù)執(zhí)行。該系統(tǒng)調(diào)用始終返回-1,并將errno設(shè)置為EINTR。
示例程序:
#include <unistd.h> #include <sys/stat.h> #include <sys/wait.h> #include <sys/types.h> #include <fcntl.h>#include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <signal.h>#define ERR_EXIT(m) \do \{ \perror(m); \exit(EXIT_FAILURE); \} while(0)void handler(int sig); void printsigset(sigset_t *set) {int i;for (i=1; i<NSIG; ++i){if (sigismember(set, i))putchar('1');elseputchar('0');}printf("\n"); }int main(int argc, char *argv[]) {sigset_t pset;sigset_t bset;sigemptyset(&bset);sigaddset(&bset, SIGINT);if (signal(SIGINT, handler) == SIG_ERR)ERR_EXIT("signal error");if (signal(SIGQUIT, handler) == SIG_ERR)ERR_EXIT("signal error");sigprocmask(SIG_BLOCK, &bset, NULL);//將信號(hào)加入進(jìn)程阻塞集中for (;;){sigpending(&pset);printsigset(&pset);sleep(1);}return 0; }void handler(int sig) {if (sig == SIGINT)printf("recv a sig=%d\n", sig);else if (sig == SIGQUIT){sigset_t uset;sigemptyset(&uset);sigaddset(&uset, SIGINT);sigprocmask(SIG_UNBLOCK, &uset, NULL);} }結(jié)果:
??? 說(shuō)明:程序首先將SIGINT信號(hào)加入進(jìn)程阻塞集(屏蔽集)中,一開(kāi)始并沒(méi)有發(fā)送SIGINT信號(hào),所以進(jìn)程未決集中沒(méi)有處于未決態(tài)的信號(hào),當(dāng)我們連續(xù)按下ctrl+c時(shí),向進(jìn)程發(fā)送SIGINT信號(hào),由于SIGINT信號(hào)處于進(jìn)程的阻塞集中,所以發(fā)送的SIGINT信號(hào)不能遞達(dá),也是就是處于未決狀態(tài),所以當(dāng)我打印未決集合時(shí)發(fā)現(xiàn)SIGINT所對(duì)應(yīng)的位為1,現(xiàn)在我們按下ctrl+\,發(fā)送SIGQUIT信號(hào),由于此信號(hào)并沒(méi)被進(jìn)程阻塞,所以SIGQUIT信號(hào)直接遞達(dá),執(zhí)行對(duì)應(yīng)的處理函數(shù),在該處理函數(shù)中解除進(jìn)程對(duì)SIGINT信號(hào)的阻塞,所以之前發(fā)送的SIGINT信號(hào)遞達(dá)了,執(zhí)行對(duì)應(yīng)的處理函數(shù),但由于SIGINT信號(hào)是不可靠信號(hào),不支持排隊(duì),所以最終只有一個(gè)信號(hào)遞達(dá)。
#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <error.h> #include <string.h> #include <unistd.h>/* 版本1, 可靠信號(hào)將被遞送多次 */ #define MYSIGNAL SIGRTMIN+5 /* 版本2, 不可靠信號(hào)只被遞送一次 */ //#define MYSIGNAL SIGTERMvoid sig_handler(int signum) {psignal(signum, "catch a signal"); }int main(int argc, char **argv) {sigset_t block, pending;int sig, flag;/* 設(shè)置信號(hào)的handler */signal(MYSIGNAL, sig_handler);/* 屏蔽此信號(hào) */sigemptyset(&block);sigaddset(&block, MYSIGNAL);printf("block signal\n");sigprocmask(SIG_BLOCK, &block, NULL);/* 發(fā)兩次信號(hào), 看信號(hào)將會(huì)被觸發(fā)多少次 */printf("---> send a signal --->\n");kill(getpid(), MYSIGNAL);printf("---> send a signal --->\n");kill(getpid(), MYSIGNAL);/* 檢查當(dāng)前的未決信號(hào) */flag = 0;sigpending(&pending);for (sig = 1; sig < NSIG; sig++) {if (sigismember(&pending, sig)) {flag = 1;psignal(sig, "this signal is pending");} }if (flag == 0) {printf("no pending signal\n");}/* 解除此信號(hào)的屏蔽, 未決信號(hào)將被遞送 */printf("unblock signal\n");sigprocmask(SIG_UNBLOCK, &block, NULL);/* 再次檢查未決信號(hào) */flag = 0;sigpending(&pending);for (sig = 1; sig < NSIG; sig++) {if (sigismember(&pending, sig)) {flag = 1;psignal(sig, "a pending signal");} }if (flag == 0) {printf("no pending signal\n");}return 0; }結(jié)果:
兩次執(zhí)行結(jié)果不同:第一次連續(xù)發(fā)送兩次不可靠信號(hào),最后解除阻塞時(shí),只有一個(gè)遞達(dá),說(shuō)明不可靠信號(hào)不支持排隊(duì)。
第二次執(zhí)行時(shí),連續(xù)兩次發(fā)送可靠信號(hào),解除阻塞后,都遞達(dá),說(shuō)明可靠信號(hào)支持排隊(duì)。
ok,這節(jié)就寫到這吧
總結(jié)
以上是生活随笔為你收集整理的信号集操作函数,信号未决、阻塞、递达的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 谷歌浏览器用的是什么内核
- 下一篇: OFD文件格式