新聞中心

EEPW首頁 > 信號通信編程實踐

信號通信編程實踐

——
作者: 時間:2007-03-05 來源: 收藏

簡單的說,信號就是在軟件層次上對中斷機制的一種模擬,是一種異步通信方式。它可以實現(xiàn)內核進程和用戶進程之間的交互。實現(xiàn)方式是,在任何時候發(fā)給某一進程,如果該進程沒有處于執(zhí)行態(tài),則該信號由內核保存,直到該進程恢復執(zhí)行再傳遞給它為止。如果一個信號進程設置為阻塞,則該信號的傳遞被延遲,直到其阻塞被取消時才被傳遞給進程。

  使用kill -l選項列出系統(tǒng)所支持的所有信號列表。我的Redhat 9.0上如下:
  
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE
 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2
13) SIGPIPE 14) SIGALRM 15) SIGTERM 17) SIGCHLD
18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN
22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO
30) SIGPWR 31) SIGSYS 33) SIGRTMIN 34) SIGRTMIN+1
35) SIGRTMIN+2 36) SIGRTMIN+3 37) SIGRTMIN+4 38) SIGRTMIN+5
39) SIGRTMIN+6 40) SIGRTMIN+7 41) SIGRTMIN+8 42) SIGRTMIN+9
43) SIGRTMIN+10 44) SIGRTMIN+11 45) SIGRTMIN+12 46) SIGRTMIN+13
47) SIGRTMIN+14 48) SIGRTMIN+15 49) SIGRTMAX-14 50) SIGRTMAX-13
51) SIGRTMAX-12 52) SIGRTMAX-11 53) SIGRTMAX-10 54) SIGRTMAX-9
55) SIGRTMAX-8 56) SIGRTMAX-7 57) SIGRTMAX-6 58) SIGRTMAX-5
59) SIGRTMAX-4 60) SIGRTMAX-3 61) SIGRTMAX-2 62) SIGRTMAX-1
63) SIGRTMAX
 

  可見信號值在31號前的有不同的名稱,這些是不可靠信號(非實時信號);后面的都是以SIGRTMIN或者SIGRTMAX開頭的信號,這些是為了解決前面“不可靠信號”的問題而進行了更改和擴充的信號,也稱為實時信號。其中RT就是Real Time的簡寫形式。

1、信號的生命周期
 
一個完整的信號生命周期可以分為3個重要階段,這三個重要階段由4個重要事件來刻畫:信號產生、信號在進程中注冊、信號在進程中注銷、執(zhí)行信號處理函數。相鄰兩個事件的時間間隔構成信號生命周期的一個階段。
 
2、信號處理過程
 
一個不可靠信號的處理過程如下:若發(fā)現(xiàn)該信號已經在進程中注冊,就忽略該信號,所以,若前一個信號還未注銷又產生了相同的信號就會造成信號丟失。
 
一個可靠信號的處理過程如下:可靠信號發(fā)送給進程,不管該信號是否已經在進程中注冊,都會被再注冊一次,因此信號不會丟失。
 
所有可靠信號都支持排隊,而不可靠信號不支持排隊。
 
3、用戶進程對信號的響應形式
 
(1)忽略信號,除SIGKILL、SIGSTOP。
(2)捕捉信號,定義信號處理函數,當信號發(fā)生則執(zhí)行相應的處理函數。
(3)缺省操作。
 
4、信號發(fā)送函數
 
kill() raise() alarm() pause()
 
實例一:保證子進程不在父進程調用kill之前退出
 
 
/*
 * kill.c
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

int main()
{
    pid_t pid;

    if ((pid = fork()) < 0) {
        perror("fork");
        exit(1);
    }
    /*child*/
    else if (pid == 0) {
        raise(SIGSTOP);
        exit(0);
    }
    /*father*/
    else {
        printf("pid = %dn", pid);
        if (waitpid(pid, NULL, WNOHANG) == 0) {
            if (kill(pid, SIGKILL) == 0) {
                printf("kill %dn", pid);
            }
            else {
                perror("kill");
                exit(1);
            }
        }/*if*/
    }/*else*/

    return 0;
}
 

執(zhí)行結果:

[armlinux@lqm kill]$ ./mykill
pid = 2032
kill 2032
 

實例二:利用alarm完成sleep功能

/*
 * alarm.c
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

void my_alarm_handle(int sign_no)
{
    if (sign_no == SIGALRM) {
        printf("I have been waken up.n");
    }
}

int main()
{
    printf("sleep for 5s ... ...n");
    signal(SIGALRM, my_alarm_handle);

    alarm(5);
    pause();

    return 0;
}
 

執(zhí)行結果:

[armlinux@lqm alarm]$ ./myalarm
sleep for 5s ... ...

等待5秒鐘后執(zhí)行處理函數,打印輸出下面內容:
I have been waken up.
 

5、信號處理集函數組

sigemptyset:初始化信號集合為空

sigfillset:初始化信號集合為所有信號的集合

sigaddset:將指定信號加入到信號集合中去

sigdelset:將指定信號從信號集中刪去

sigismember:查詢指定信號是否在信號集合之中

sigprocmask:判斷檢測或更改信號屏蔽字

sigaction:用于改變進程接收到特定信號之后的行為

實踐三:練習信號處理集函數

/*
 * 信號集函數組練習
 * 數據結構sigaction
 * struct sigaction {
 * void (*sa_handler)(int signo);
 * sigset_t sa_mask;
 * int sa_flags;
 * void (*sa_restore)(void);
 * }
 */

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

/*自定義SIGINT的處理函數,如果你按ctrl+c,則會打印提示,而不是默認的退出*/
void my_func(int sigo_num)
{
    printf("If you want to quit, please try 'ctrl+\' .n");
}

int main()
{
    sigset_t set;
    struct sigaction action1, action2;

    /*初始化信號集為空*/
    if (sigemptyset(&set) < 0) {
        perror("sigemptyset");
        exit(1);
    }

    /*將相應的信號加入信號集*/
    if (sigaddset(&set, SIGQUIT) < 0) {
        perror("sigaddset SIGQUIT");
        exit(1);
    }
    if (sigaddset(&set, SIGINT) < 0) {
        perror("sigaddset SIGINT");
        exit(1);
    }

    /*設置信號屏蔽字*/
    if (sigprocmask(SIG_BLOCK, &set, NULL) < 0) {
        perror("sigprocmask SIG_BLOCK");
        exit(1);
    }
    else {
        printf("blocked,and sleep for 5s ...n");
        sleep(5);
    }
    if (sigprocmask(SIG_UNBLOCK, &set, NULL) < 0) {
        perror("sigprocmask SIG_UNBLOCK");
        exit(1);
    }
    else {
        printf("unblockn");
        /*此處可以添加函數功能模塊process()*/
        sleep(2);
        printf("If you want to quit this program, please try ...n");
    }

    /*對相應的信號進行循環(huán)處理*/
    while (1) {
        if (sigismember(&set, SIGINT)) {
            sigemptyset(&action1.sa_mask);
            action1.sa_handler = my_func;
            sigaction(SIGINT, &action1, NULL);
        }
        else if (sigismember(&set, SIGQUIT)) {
            sigemptyset(&action2.sa_mask);
            /*SIG_DFL采用缺省的方式處理*/
            action2.sa_handler = SIG_DFL;
            sigaction(SIGTERM, &action2, NULL);
        }
    }

    return 0;
}
 

執(zhí)行處理:

[armlinux@lqm sigaction]$ ./sigaction
blocked,and sleep for 5s ...
unblock
If you want to quit this program, please try ...
If you want to quit, please try 'ctrl+' .
退出



關鍵詞: 信號通信

評論


技術專區(qū)

關閉