信号集
信号集是表示多個信号的資料類型,這裡的信号集資料類型是 sigset_t,包含五個處理信号集的函數:
/* 信号集 */
#include <signal.h>
int sigemptyset(sigset_t *set);//初始化由set所指向的信号集,清空信号集;
int sigfillset(sigset_t *set);//初始化由set所指向的信号集,使其包括所有信号;
int sigaddset(sigset_t *set, int signo);//把指定的信号signo添加到由set所指的信号集中;
int sigdelset(sigset_t *set, int signo);//把指定的信号signo從由set所指定的信号集中删除;
//前面四個函數傳回值:若成功則傳回0,若出錯則傳回-1;
int sigismember(const sigset_t *set, int signo);//判斷指定的信号signo是否在由set所指的信号集中;
//傳回值:若為真則傳回1,若為假則傳回0,若出錯則傳回-1;
/*
* 說明:
* 所有應用程式使用信号集之前,要對該信号集調用sigemptyset或sigfillset一次;
*/
sigprocmask 函數
在前面我們提到,task_struct 結構有一個blocked 成員(我們稱之為“信号屏蔽字”),它指定了程序阻塞的信号,被阻塞的信号将不能被遞送給程序,直到程序解除阻塞。在信号被阻塞時,核心将其放置到待決清單上。如果同一個信号在阻塞期間被發送了多次,則在待決清單中隻放置一次。也就是說,不管發送了多少相同的信号,在程序删除阻塞後,都隻會接收到一個信号。調用函數sigprocmask 可以檢測或更改其信号屏蔽字。在調用 sigprocmask 後如果有任何未決的、不再阻塞的信号,則在 sigprocmask 傳回前,至少會将其中一個信号遞送給該程序。
/* sigprocmask 函數 */
/*
* 函數功能:檢查或更改信号屏蔽字,也可同時執行這兩個操作;
* 傳回值:若成功則傳回0,若出錯則傳回-1;
* 函數原型:
*/
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
/*
* 說明:
* 若oset是非空指針,那麼程序的目前信号屏蔽字通過oset傳回;
* 若set是非空指針,則參數how訓示如何修改目前信号屏蔽字;
* 若set是空指針,則不改變該程序的信号屏蔽字,how的值就沒有意義;
* 參數how可選以下值:
* (1)SIG_BLOCK 該程序新的信号屏蔽字是其目前信号屏蔽字和set指向信号集的并集。set包含了我們希望阻塞的附加信号;
* (2)SIG_UNBLOCK 該程序新的信号屏蔽字是其目前信号屏蔽字和set指向信号集補集的交集;set包含我們希望解除阻塞的附加信号;
* (3)SIG_SETMASK 該程序新的信号屏蔽字将被set指向的信号集的值所代替;
* SIG_BLOCK是"或"操作,而SIG_SETMASK則是指派操作;
* 注意:SIGKILL 和 SIGSTOP 信号是不能阻塞的;
*/
sigpending 函數
sigpending 函數傳回信号集,其中的各個信号對于調用程序是阻塞的而不能傳遞,該信号集通過set參數傳回。
/* sigpending函數 */
/*
* 函數功能:傳回信号集;
* 傳回值:若成功則傳回0,若出錯則傳回-1;
* 函數原型:
*/
#include <signal.h>
int sigpending(sigset_t *set);
測試程式:
#include "apue.h"
#include <sys/wait.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <signal.h>
static void sig_quit(int signo);
int main()
{
sigset_t newmask,oldmask,pendmask;
if(signal(SIGQUIT,sig_quit) == SIG_ERR)
{
err_sys("signal() error");
exit(-1);
}
//初始化信号集
sigemptyset(&newmask);
//添加一個SIGQUIT信号
sigaddset(&newmask,SIGQUIT);
//将newmask信号集設定為阻塞,原信号集儲存在oldmask中
if(sigprocmask(SIG_BLOCK,&newmask,&oldmask) == -1)
{
err_sys("SIG_BLOCK error");
exit(-1);
}
sleep(5);
//擷取阻塞的信号集
if(sigpending(&pendmask) == -1)
{
err_sys("sigpending() error");
exit(-1);
}
//判斷SIGQUIT是否是阻塞的
if(sigismember(&pendmask,SIGQUIT))
printf("\nSIGQUIT is pending.\n");
//恢複原始的信号集
if(sigprocmask(SIG_SETMASK,&oldmask,NULL) == -1)
{
err_sys("SIG_SETMASK error");
exit(-1);
}
printf("SITQUIT unblocked\n");
sleep(5);
exit(0);
}
static void sig_quit(int signo)
{
printf("caught SIGQUIT.\n");
if(signal(SIGQUIT,SIG_DFL) == SIG_ERR)
{
err_sys("can't reset SIGQUIT");
exit(-1);
}
}
輸出結果:
$ ./sigset
^\
SIGQUIT is pending.
caught SIGQUIT.
SITQUIT unblocked
$ ./sigset
^\^\^\^\^\^\
SIGQUIT is pending.
caught SIGQUIT.
SITQUIT unblocked
在程式第二次 sleep 時,産生了多個 SIGQUIT 信号,此時被 pending,解除了 mask 後,隻産生了一次 action,也說明了在同一時刻産生多次同一種信号,不會對信号排隊。
參考資料:
《UNIX進階環境程式設計》