1. 程式人生 > >linux通過訊號程序間通訊例項理解

linux通過訊號程序間通訊例項理解

在linux系統程式設計的學習中,通過訊號進行程序簡編譯是一大重點
本文通過一個例項加強對sigemptyset、sigprocmask的理解

int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);

其中 signum 為收到的訊號

其中

struct sigaction
{
    void    (*sa_handler)(int); //      }  
    void    (*sa_sigaction)(int, siginfo_t *, void *);//  }  兩個函式指標僅有一個有效
sigset_t sa_mask; //阻塞訊號集 int sa_flags; //若sa_flags==0則*sa_handler;有效,若sa_flags==SA_SIGINFO則*sa_sigaction有效 void (*sa_restorer)(void);//擴充套件 }
其中sigset_t 為一個結構體,訊號在int __val[32] 中以掩碼儲存,有32位二進位制數,以對應一位標‘1’來儲存對應訊號

我們也可以通過

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);//  在程序阻塞訊號集裡,增加或刪除訊號
其中int how 有如下三種引數,均針對oldset
            SIG_BLOCK   //增加
            SIG_UNBLOCK  //刪除
            SIG_SETMASK  //先清空程序阻塞集號,再增加

值得一提的是訊號在訊號集中的儲存並非簡單賦值,而是以掩碼的形式儲存,2進位制數不同位標‘1’表示不同命令的儲存。在此並不詳談。

當程序訊號集中存在某一訊號SIG***時,向該程序傳送此訊號則會被阻塞,直至sa_flags對應的函式被執行完成為止。
以下為例項方便理解:
例項一:

#include <stdio.h>
#include <signal.h>
#include <stdlib.h> #include <unistd.h> pid_t i,j; void f(int sig) { if(kill(i,SIGINT)<0) { perror("kill fail"); } if(kill(j,SIGINT)<0) { perror("kill fail"); } wait(i,NULL,0); wait(j,NULL,0); printf("Parent process exit!\n"); exit(0); } void f_1(int sig) { printf("Child process 1 is killed by parent!\n"); } void f_2(int sig) { printf("Child process 2 is killed by parent!\n"); } int main() { i = fork(); if(i<0) { perror("fork fail"); return -1; } else if(i==0) { signal(SIGINT,f_1); pause(); } else if(i>0) { j = fork(); if(j<0) { perror("fork fail"); return -1; } if(j==0) { signal(SIGINT,f_2);//收到SIGINT訊號則執行f_2動作 pause(); } if(j>0) { signal(SIGINT,f); pause(); } } }

例項二:

#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
int output(sigset_t set)
{
    printf("set.val[0]=%x\n",(int)set.__val[0]);
}

void handler(int sig)
{
    int i;
    sigset_t sysset;
    printf("\n nin hadler sig=%d\n",sig);
    sigprocmask(SIG_SETMASK,NULL,&sysset);
    output(sysset);
    printf("return\n");
}

int main()
{
    struct sigaction act;
    sigset_t set,sysset,newset;//自定義訊號集合
    sigemptyset(&set);
    sigemptyset(&newset);//清空
    sigaddset(&set,SIGUSR1);//向程序阻塞訊號集中傳送訊號SIGUSR1
    sigaddset(&newset,SIGUSR2);
    printf("\nadd sigusr1,the value of set");
    output(set);//測試
    printf("\nadd sigusr2,the value of newset");
    output(newset);
    printf("\nafter set proc block set ,and then read to sysset\n");
    sigprocmask(SIG_SETMASK,&set,NULL);
    //將系統阻塞訊號集清空,然後拷貝訊號集set的內容到系統阻塞訊號集中;

    sigprocmask(SIG_SETMASK,NULL,&sysset);
    //將訊號集sysset中的內容清空,然後拷貝系統阻塞訊號集中的內容到sysset
    printf("system mask is:\n");
    output(sysset);//測試,此時系統阻塞訊號集的內容為SIGUSR1
    printf("set mask is:\n");
    output(set);
    printf("install sigalrm,and the act.sammask is newset(siguser2)\n");
    act.sa_handler=handler;//在另一終端中輸入kill -SIGUSR1 [該程序pid] 並不會立刻執行該訊號相應動作,直到handler函式執行完畢
    act.sa_flags=0;
    act.sa_mask=newset;
    sigaction(SIGALRM,&act,NULL);//pause中斷程序,直至收到“SIGALRM”訊號重新啟用,執行act所包含的動作。
    pause();

    printf("after exec isr\n");
    sigemptyset(&sysset);//清空sysset
    sigprocmask(SIG_SETMASK,NULL,&sysset);
    output(sysset);
}