天天看點

Liunx系統程式設計篇—程序通信(五)信号(二)(sigaction、sigqueue)

本文承接上文Liunx系統程式設計篇—程序通信(五)信号(一)(原理、概述、建立、實戰)(kill、signal)上文對于信号的一些理論,本文就不再贅述。

本文重點是講解:sigaction、sigqueue兩個函數,分别用于信号處理函數的注冊、信号處理發送函數是signal和kill的更新版。

常用API

信号處理函數的注冊

入門版:函數signal

進階版:函數sigaction

信号處理發送函數

1.入門版:kill

2.進階版:sigqueue

對于入門版的信号處理API的重點在于動作,但kill 函數發送的信号是無法攜帶資料。

對于進階版的信号處理API的==重點信号攜帶的資訊

sigaction函數

sigaction 是一個系統調用,可以用來查詢或設定信号處理方式。

包含的頭檔案

函數原型:

signum:參數指出要捕獲的信号類型。

act:參數指定新的信号處理方式,struct sigaction類型如果不為空說明需要對該信号有新的配置。

oldact:備份,如果不為空,那麼可以對之前的信号配置進行備份,以友善之後進行恢複。

struct sigaction結構體介紹

struct sigaction {
   void (*sa_handler)(int); //信号處理程式,不接受額外資料,SIG_IGN 為忽略,SIG_DFL 為預設動作
   void (*sa_sigaction)(int, siginfo_t *, void *); //信号處理程式,能夠接受額外資料和sigqueue配合使用
   sigset_t sa_mask;//阻塞關鍵字的信号集,可以再調用捕捉函數之前,把信号添加到信号阻塞字,信号捕捉函數傳回之前恢複為原先的值。
   int sa_flags;//影響信号的行為SA_SIGINFO表示能夠接受資料
 };
//回調函數句柄sa_handler、sa_sigaction隻能任選其一
           
sa_handler

sa_handler此參數和signal()的參數handler相同,代表新的信号處理函數

void (*sa_sigaction)(int, siginfo_t *, void *);

關于

void (*sa_sigaction)(int, siginfo_t *, void *);

處理函數來說還需要有一些說明。

void* 是接收到信号所攜帶的額外資料;

而struct siginfo這個結構體主要适用于記錄接收信号的一些相關資訊。

siginfo_t {
               int      si_signo;    /* Signal number */
               int      si_errno;    /* An errno value */
               int      si_code;     /* Signal code */
               int      si_trapno;   /* Trap number that caused
                                        hardware-generated signal
                                        (unused on most architectures) */
               pid_t    si_pid;      /* Sending process ID */
               uid_t    si_uid;      /* Real user ID of sending process */
               int      si_status;   /* Exit value or signal */
               clock_t  si_utime;    /* User time consumed */
               clock_t  si_stime;    /* System time consumed */
               sigval_t si_value;    /* Signal value */
               int      si_int;      /* POSIX.1b signal */
               void    *si_ptr;      /* POSIX.1b signal */
               int      si_overrun;  /* Timer overrun count; POSIX.1b timers */
               int      si_timerid;  /* Timer ID; POSIX.1b timers */
               void    *si_addr;     /* Memory location which caused fault */
               int      si_band;     /* Band event */
               int      si_fd;       /* File descriptor */
}
           

其中的成員很多,si_signo 和 si_code 是必須實作的兩個成員。可以通過這個結構體擷取到信号的相關資訊。

關于發送過來的資料是存在兩個地方的,sigval_t si_value這個成員中有儲存了發送過來的資訊;

同時,在si_int或者si_ptr成員中也儲存了對應的資料。

sa_mask

sa_mask 用來設定在處理該信号時暫時将sa_mask 指定的信号集擱置

sa_mask 成員,設定在其的信号集中的信号,會在捕捉函數調用前設定為阻塞,并在捕捉函數傳回時恢複預設原有設定。這樣的目的是,在調用信号處理函數時,就可以阻塞默寫信号了。在信号處理函數被調用時,作業系統會建立新的信号阻塞字,包括正在被遞送的信号。是以,可以保證在處理一個給定信号時,如果這個種信号再次發生,那麼他會被阻塞到對之前一個信号的處理結束為止。

sa_flags

sa_flags 用來設定信号處理的其他相關操作,下列的數值可用:

SA_RESETHAND:當調用信号處理函數時,将信号的處理函數重置為預設值SIG_DFL

SA_RESTART:如果信号中斷了程序的某個系統調用,則系統自動啟動該系統調用

SA_NODEFER :一般情況下, 當信号處理函數運作時,核心将阻塞該給定信号。但是如果設定了 SA_NODEFER标記, 那麼在該信号處理函數運作時,核心将不會阻塞該信号

sigqueue函數

在隊列中向指定程序發送一個信号和資料

包含的頭檔案

函數原型:

union sigval {
   int   sival_int;
   void *sival_ptr;
 };
           

pid:發給誰,是目标程序的程序号

sig:發的是什麼信号,是信号代号

value:發送的消息(int或者char*),是一個聯合體,表示信号附帶的資料,附帶資料可以是一個整數也可以是一個指針,有如下形式:

union sigval {
	int sival_int;
	void *sival_ptr;//指向要傳遞的信号參數
};value
           

使用這個函數之前,必須要有幾個操作需要完成

1、使用 sigaction 函數安裝信号處理程式時,制定了 SA_SIGINFO 的标志=。

2、sigaction 結構體中的sa_sigaction成員提供了信号捕捉函數。如果實作的sa_handler成員,那麼将無法擷取額外攜帶的資料。

3、sigqueue 函數隻能把信号發送給單個程序,可以使用 value 參數向信号處理程式傳遞整數值或者指針值。

4、、sigqueue 函數不但可以發送額外的資料,還可以讓信号進行排隊(作業系統必須實作了 POSIX.1的實時擴充),對于設定了阻塞的信号,使用 sigqueue 發送多個同一信号,在解除阻塞時,接受者會接收到發送的信号隊列中的信号,而不是直接收到一次。但是,信号不能無限的排隊,信号排隊的最大值受到SIGQUEUE_MAX的限制,達到最大限制後,sigqueue 會失敗,errno 會被設定為 EAGAIN。

執行個體:

demo.c

#include<stdio.h>
#include <signal.h>
/*信号處理函數*/
void handler(int signum, siginfo_t *info, void *context)
{
        printf("get signum %d\n",signum);
        if(context!=NULL){//如果有内容
                printf("get data=%d\n",info->si_int);
                printf("get data=%d\n",info->si_value.sival_int);
        }
}
int main()
{
        struct sigaction act;
        act.sa_sigaction = handler;//信号處理程式,能夠接受額外資料和sigqueue配合使用
        act.sa_flags = SA_SIGINFO;//影響信号的行為SA_SIGINFO表示能夠接受資料
        sigaction(SIGUSR1,&act,NULL);
        sigaction(SIGINT,&act,NULL);
        while(1);
        return 0;
}
           

send.c

#include <signal.h>
#include <stdio.h>
int main(int argc,char **argv)
{
        int pid = atoi(argv[2]);
        int signum = atoi(argv[1]);
        union sigval value;
        value.sival_int = 100;
        sigqueue(pid,signum,value);//信号處理發送函數
        printf("done\n");
        return 0;
}
           

實驗結果:

Liunx系統程式設計篇—程式通信(五)信号(二)(sigaction、sigqueue)

繼續閱讀