我們已經(jīng)知道,我們可以通過(guò)信號(hào)來(lái)終止進(jìn)程,也可以通過(guò)信號(hào)來(lái)在進(jìn)程間進(jìn)行通信,程序也可以通過(guò)指定信號(hào)的關(guān)聯(lián)處理函數(shù)來(lái)改變信號(hào)的默認(rèn)處理方式,也可以屏蔽某些信號(hào),使其不能傳遞給進(jìn)程。那么我們應(yīng)該如何設(shè)定我們需要處理的信號(hào),我們不需要處理哪些信號(hào)等問(wèn)題呢?信號(hào)集函數(shù)就是幫助我們解決這些問(wèn)題的。
有關(guān)Linux進(jìn)程間使用信號(hào)通信的更多內(nèi)容,可以參閱我的另一篇文章,Linux進(jìn)程間通信 -- 信號(hào)量函數(shù) signal()、sigaction()
下面是信號(hào)函數(shù)集:
1、int sigemptyset(sigset_t *set);
該函數(shù)的作用是將信號(hào)集初始化為空。
2、int sigfillset(sigset_t *set);
該函數(shù)的作用是把信號(hào)集初始化包含所有已定義的信號(hào)。
3、int sigaddset(sigset_t *set, int signo);
該函數(shù)的作用是把信號(hào)signo添加到信號(hào)集set中,成功時(shí)返回0,失敗時(shí)返回-1。
4、int sigdelset(sigset_t *set, int signo);
該函數(shù)的作用是把信號(hào)signo從信號(hào)集set中刪除,成功時(shí)返回0,失敗時(shí)返回-1.
5、int sigismember(sigset_t *set, int signo);
該函數(shù)的作用是判斷給定的信號(hào)signo是否是信號(hào)集中的一個(gè)成員,如果是返回1,如果不是,返回0,如果給定的信號(hào)無(wú)效,返回-1;
6、int sigpromask(int how, const sigset_t *set, sigset_t *oset);
該函數(shù)可以根據(jù)參數(shù)指定的方法修改進(jìn)程的信號(hào)屏蔽字。新的信號(hào)屏蔽字由參數(shù)set(非空)指定,而原先的信號(hào)屏蔽字將保存在oset(非空)中。如果set為空,則how沒(méi)有意義,但此時(shí)調(diào)用該函數(shù),如果oset不為空,則把當(dāng)前信號(hào)屏蔽字保存到oset中。
how 的不同取值及操作如下所示:
如果sigpromask成功完成返回0,如果how取值無(wú)效返回-1,并設(shè)置errno為EINVAL。
注意:調(diào)用這個(gè)函數(shù)才能改變進(jìn)程的屏蔽字,之前的函數(shù)都是為改變一個(gè)變量的值而已,并不會(huì)真正影響進(jìn)程的屏蔽字。
7、int sigpending(sigset_t *set);
該函數(shù)的作用是將被阻塞的信號(hào)中停留在待處理狀態(tài)的一組信號(hào)寫(xiě)到參數(shù)set指向的信號(hào)集中,成功調(diào)用返回0,否則返回-1,并設(shè)置errno表明錯(cuò)誤原因。
8、int sigsuspend(const sigset_t *sigmask);
該函數(shù)通過(guò)將進(jìn)程的屏蔽字替換為由參數(shù)sigmask給出的信號(hào)集,然后掛起進(jìn)程的執(zhí)行。注意操作的先后順序,是先替換再掛起程序的執(zhí)行。程序?qū)⒃谛盘?hào)處理函數(shù)執(zhí)行完畢后繼續(xù)執(zhí)行。如果接收到信號(hào)終止了程序,sigsuspend()就不會(huì)返回,如果接收到的信號(hào)沒(méi)有終止程序,sigsuspend()就返回-1,并將errno設(shè)置為EINTR。
特別提醒:如果一個(gè)信號(hào)被進(jìn)程阻塞,它就不會(huì)傳遞給進(jìn)程,但會(huì)停留在待處理狀態(tài),當(dāng)進(jìn)程解除對(duì)待處理信號(hào)的阻塞時(shí),待處理信號(hào)就會(huì)立刻被處理。
下面以一個(gè)例子來(lái)說(shuō)明上述函數(shù)的用法,源文件為 sigset.c,代碼如下:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void handler(int sig)
{
printf('Handle the signal %d\n', sig);
}
int main(int argc, char **argv)
{
sigset_t sigset; // 用于記錄屏蔽字
sigset_t ign; // 用于記錄被阻塞(屏蔽)的信號(hào)集
struct sigaction act;
// 清空信號(hào)集
sigemptyset(&sigset);
sigemptyset(&ign);
// 向信號(hào)集中添加 SIGINT
sigaddset(&sigset, SIGINT);
// 設(shè)置處理函數(shù) 和 信號(hào)集
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, 0);
printf('Wait the signal SIGNAL...\n');
pause();
// 設(shè)置進(jìn)程屏蔽字, 在本例中為屏蔽 SIGINT
sigprocmask(SIG_SETMASK, &sigset, 0);
printf('Please press Ctrl + C in 10 seconds...\n');
sleep(10);
// 測(cè)試 SIGINT 是否被屏蔽
sigpending(&ign);
if (sigismember(&ign, SIGINT))
{
printf('The SIGINT signal has ignored\n');
}
// 從信號(hào)集中刪除信號(hào) SIGINT
sigdelset(&sigset, SIGINT);
printf('Wait the signal SIGINT...\n');
// 將進(jìn)程的屏蔽字重新設(shè)置, 即取消對(duì) SIGINT 的屏蔽
// 并掛起進(jìn)程
sigsuspend(&sigset);
printf('The app will exit in 5 secondes!\n');
sleep(5);
return 0;
}
運(yùn)行結(jié)果如下:
首先,我們能過(guò)sigaction()函數(shù)改變了SIGINT信號(hào)的默認(rèn)行為,使之執(zhí)行指定的函數(shù)handler,所以輸出了語(yǔ)句:Handle the signal 2。然后,通過(guò)sigprocmask()設(shè)置進(jìn)程的信號(hào)屏蔽字,把SIGINT信號(hào)屏蔽起來(lái),所以過(guò)了10秒之后,用sigpending()函數(shù)去獲取被阻塞的信號(hào)集時(shí),檢測(cè)到了被阻塞的信號(hào)SIGINT,輸出The SIGINT signal has ignored。最后,用函數(shù)sigdelset()函數(shù)去除先前用sigaddset()函數(shù)加在sigset上的信號(hào)SIGINT,再調(diào)用函數(shù)sigsuspend(),把進(jìn)程的屏蔽字再次修改為sigset(不包含SIGINT),并掛起進(jìn)程。由于先前的SIGINT信號(hào)停留在待處理狀態(tài),而現(xiàn)在進(jìn)程已經(jīng)不再阻塞該信號(hào),所以進(jìn)程馬上對(duì)該信號(hào)進(jìn)行處理,從而在最后,你不用輸入 Ctrl+C 也會(huì)出現(xiàn)后面的處理語(yǔ)句(可參閱前面特別提醒的內(nèi)容),最后過(guò)了5秒程序就成功退出了。
聯(lián)系客服