Linux進程間通訊(二):信號集函數 sigemptyset()、sigprocmask()、sigpending()、sigsuspend()

咱們已經知道,咱們能夠經過信號來終止進程,也能夠經過信號來在進程間進行通訊,程序也能夠經過指定信號的關聯處理函數來改變信號的默認處理方式,也能夠屏蔽某些信號,使其不能傳遞給進程。那麼咱們應該如何設定咱們須要處理的信號,咱們不須要處理哪些信號等問題呢?信號集函數就是幫助咱們解決這些問題的。php

有關Linux進程間使用信號通訊的更多內容,能夠參閱個人另外一篇文章,Linux進程間通訊 -- 信號量函數 signal()、sigaction()html

下面是信號函數集:編程

一、int sigemptyset(sigset_t *set);服務器

該函數的做用是將信號集初始化爲空。app

二、int sigfillset(sigset_t *set);函數

該函數的做用是把信號集初始化包含全部已定義的信號。性能

三、int sigaddset(sigset_t *set, int signo);測試

該函數的做用是把信號signo添加到信號集set中,成功時返回0,失敗時返回-1。ui

四、int sigdelset(sigset_t *set, int signo);spa

該函數的做用是把信號signo從信號集set中刪除,成功時返回0,失敗時返回-1.

五、int sigismember(sigset_t *set, int signo);

該函數的做用是判斷給定的信號signo是不是信號集中的一個成員,若是是返回1,若是不是,返回0,若是給定的信號無效,返回-1;

六、int sigpromask(int how, const sigset_t *set, sigset_t *oset);

該函數能夠根據參數指定的方法修改進程的信號屏蔽字。新的信號屏蔽字由參數set(非空)指定,而原先的信號屏蔽字將保存在oset(非空)中。若是set爲空,則how沒有意義,但此時調用該函數,若是oset不爲空,則把當前信號屏蔽字保存到oset中。

how 的不一樣取值及操做以下所示:

若是sigpromask成功完成返回0,若是how取值無效返回-1,並設置errno爲EINVAL。

注意:調用這個函數才能改變進程的屏蔽字,以前的函數都是爲改變一個變量的值而已,並不會真正影響進程的屏蔽字。

七、int sigpending(sigset_t *set);

該函數的做用是將被阻塞的信號中停留在待處理狀態的一組信號寫到參數set指向的信號集中,成功調用返回0,不然返回-1,並設置errno代表錯誤緣由。

八、int sigsuspend(const sigset_t *sigmask);

該函數經過將進程的屏蔽字替換爲由參數sigmask給出的信號集,而後掛起進程的執行。注意操做的前後順序,是先替換再掛起程序的執行。程序將在信號處理函數執行完畢後繼續執行。若是接收到信號終止了程序,sigsuspend()就不會返回,若是接收到的信號沒有終止程序,sigsuspend()就返回-1,並將errno設置爲EINTR。

特別提醒:若是一個信號被進程阻塞,它就不會傳遞給進程,但會停留在待處理狀態,當進程解除對待處理信號的阻塞時,待處理信號就會馬上被處理。

下面以一個例子來講明上述函數的用法,源文件爲 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;		// 用於記錄被阻塞(屏蔽)的信號集
	struct sigaction act;

	// 清空信號集
	sigemptyset(&sigset);
	sigemptyset(&ign);

	// 向信號集中添加 SIGINT
	sigaddset(&sigset, SIGINT);

	// 設置處理函數 和 信號集
	act.sa_handler = handler;
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	sigaction(SIGINT, &act, 0);

	printf("Wait the signal SIGNAL...\n");
	pause();

	// 設置進程屏蔽字, 在本例中爲屏蔽 SIGINT
	sigprocmask(SIG_SETMASK, &sigset, 0);
	printf("Please press Ctrl + C in 10 seconds...\n");
	sleep(10);

	// 測試 SIGINT 是否被屏蔽
	sigpending(&ign);
	if (sigismember(&ign, SIGINT))
	{
		printf("The SIGINT signal has ignored\n");
	}

	// 從信號集中刪除信號 SIGINT
	sigdelset(&sigset, SIGINT);
	printf("Wait the signal SIGINT...\n");

	// 將進程的屏蔽字從新設置, 即取消對 SIGINT 的屏蔽
	// 並掛起進程
	sigsuspend(&sigset);

	printf("The app will exit in 5 secondes!\n");
	sleep(5);

	return 0;
}

運行結果以下:

首先,咱們能過sigaction()函數改變了SIGINT信號的默認行爲,使之執行指定的函數handler,因此輸出了語句:Handle the signal 2。而後,經過sigprocmask()設置進程的信號屏蔽字,把SIGINT信號屏蔽起來,因此過了10秒以後,用sigpending()函數去獲取被阻塞的信號集時,檢測到了被阻塞的信號SIGINT,輸出The SIGINT signal has ignored。最後,用函數sigdelset()函數去除先前用sigaddset()函數加在sigset上的信號SIGINT,再調用函數sigsuspend(),把進程的屏蔽字再次修改成sigset(不包含SIGINT),並掛起進程。因爲先前的SIGINT信號停留在待處理狀態,而如今進程已經再也不阻塞該信號,因此進程立刻對該信號進行處理,從而在最後,你不用輸入 Ctrl+C 也會出現後面的處理語句(可參閱前面特別提醒的內容),最後過了5秒程序就成功退出了。

 

 

參考:

http://blog.csdn.net/ljianhui/article/details/10130539

《Linux 高性能服務器編程》

相關文章
相關標籤/搜索