1. 程式人生 > >[領卓教育]linux通訊——訊號(SIGNAL)

[領卓教育]linux通訊——訊號(SIGNAL)

1.訊號 1) 是在軟體層次上對中斷機制的一種模擬,非同步通訊 2)可以直接進行使用者空間程序和核心程序之間互動,核心程序也可以利用它來通知使用者空間 程序發生了哪些系統事件。 3)如果該程序當前並未處於執行態,則該訊號就由核心儲存起來,知道該程序恢復執行再傳遞給他; 如果一個訊號被程序設定為阻塞,則該訊號的傳遞被延遲,知道阻塞取消時才被傳遞給程序。 2.系統定義的訊號 (kill -l) 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 16) SIGSTKFLT 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 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX 訊號從1 到31 是系統早期定義的訊號, 不實時訊號 訊號從34 到64 後期補充的訊號, 是實時訊號

3.使用者程序對訊號的響應方式: 忽略訊號:對訊號不做任何處理。 捕捉訊號:定義訊號處理函式,當訊號發生時,執行相應的處理函式。 但是有兩個訊號不能處理不能忽略:即SIGKILL及SIGSTOP。 4. 執行預設操作:Linux對每種訊號都規定了預設操作 SIGHUP :預設行為 : 殺死, 該訊號在使用者終端連線(正常或非正常)結束時發出 SIGINT :預設行為 : 殺死 該訊號在使用者鍵入INTR字元(通常是Ctrl+C)時發出,終端驅動程式傳送此訊號並送到前臺程序中的每一個程序。 SIGQUIT:預設行為 : 殺死, 該訊號和SIGINT類似,但由QUIT字元(通常是Ctrl + )來控制。 SIGKILL:預設行為 : 殺死, 不能捕捉也不能被忽略 SIGALRM:預設行為 : 殺死 , 定時時間到發出 SIGSTOP:預設行為 : 暫停,不能捕捉也不能被忽略 SIGTSTP: 預設行為 : 暫停, 可以被捕捉可忽略,(通常是Ctrl-Z)發出這個訊號。 SIGCHLD: 預設行為 : 忽略,子程序改變狀態時,父程序會收到這個訊號 SIGUSR1 :預設行為 :殺死 使用者可以使用的訊號, SIGUSR2 :預設行為 :殺死 使用者可以使用的訊號,

練習1:編寫一段程式,使用系統呼叫fork( )建立兩個子程序,再用系統呼叫signal( ) 讓父程序捕捉鍵盤上來的中斷訊號(即按ctrl+c鍵 SIGINT),當捕捉到中斷訊號後,父程序用系統呼叫kill( )向兩個子程序發出訊號,子程序捕捉到父程序發來的訊號後,分別輸出下列資訊後終止: Child process 1 is killed by parent! Child process 2 is killed by parent! 父程序等待兩個子程序終止後,輸出以下資訊後終止: Parent process exit!

結果:
child2 is running !
child1 is running !
child2 is running !
child1 is running !
child2 is running !
child1 is running !
^Cchild2 is killed by parent !
child1 is killed by parent !
parent is exit

程式碼:

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

pid_t pid_child1,pid_child2 ;//定義兩個程序號用來儲存子程序的pid
void stop(int signum)
{
    if(signum == SIGINT)//捕捉到由父程序接收到的Ctrl+c訊號
    {
        //給兩個子程序傳送訊號
        kill(pid_child1,SIGUSR1) ;
        kill(pid_child2,SIGUSR2) ;
    }
    if(signum == SIGUSR1)//子程序1捕捉到由父程序傳送的SIGUSR1訊號
    {
        printf("child1 is killed by parent !\n") ;
        exit(0) ;
    }
    if(signum == SIGUSR2)//子程序2捕捉到由父程序傳送的SIGUSR2訊號
    {
        printf("child2 is killed by parent !\n") ;
        exit(0) ;
    }
}

int main(int argc, const char *argv[])
{
    pid_t pid ;
    pid = fork() ;
    if(pid < 0)
    {
        perror("fork") ;
        exit(-1) ;
    }
    else if(pid == 0)//子程序1
    {
        signal(SIGINT,SIG_IGN) ;//子程序忽略Ctrl+c訊號
        signal(SIGUSR1,stop) ;//使用者自定義訊號,處理stop函式
        while(1)
        {
            printf("child1 is running !\n") ;
            sleep(1) ;
        }
    }
    else
    {
        pid_child1 = pid ;//用pid_child1儲存父程序返回的子程序1的pid
        pid = fork() ;
        if(pid < 0)
        {
            perror("fork2") ;
            exit(-1) ;
        }
        else if(pid == 0)//子程序2
        {
            signal(SIGINT,SIG_IGN) ;//子程序忽略Ctrl+c訊號
            signal(SIGUSR2,stop) ;//使用者自定義訊號,處理stop函式
            while(1)
            {
                printf("child2 is running !\n") ;
                sleep(1) ;
            }
        }
        else //parent
        {
            pid_child2 = pid ;//儲存父程序返回的子程序2的pid
            signal(SIGINT,stop) ;
            signal(SIGCHLD,stop) ;
            /************等待兩個子程序都退出後***************/
            /************父程序執行相應動作*******************/
            waitpid(pid_child1,NULL,0) ;
            waitpid(pid_child2,NULL,0) ;
            printf("parent is exit\n") ;
            exit(0) ;
        }
    }
    return 0;
}

練習2: 司機售票員問題 建立子程序代表售票員,父程序代表司機 ,同步過程如下: 售票員捕捉SIGINT(代表開車)(父程序忽略這個訊號),發SIGUSR1給司機,司機列印(“let’s gogogo”) 售票員捕捉SIGQUIT(代表停車)(父程序忽略這個訊號),發SIGUSR2給司機,司機列印(“stop the bus”) 司機捕捉SIGTSTP(代表車到總站)(子程序忽略這個訊號),發SIGUSR1給售票員,售票員列印(“please get off the bus”)

結果:
^CLet`s go go go !
^Zplease get off the bus !
^\stop the bus !

程式碼:

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

pid_t pid_child ;

void sighandler_child(int signum) 
{
    if(signum == SIGINT)
    {
        kill(getppid(),SIGUSR1) ;
    }
    if(signum == SIGQUIT)
    {
        kill(getppid(),SIGUSR2) ;
    }
    if(signum == SIGUSR1)
    {
        printf("please get off the bus !\n") ;
    }
}
void sighandler_parent(int signum)
{
    if(signum == SIGUSR1)
    {
        printf("Let`s go go go !\n") ;
    }

    if(signum == SIGUSR2)
    {
        printf("stop the bus !\n") ;
        exit(0) ;
    }
    if(signum == SIGTSTP)
    {
        kill(pid_child,SIGUSR1) ;
    }
}
int main(int argc, const char *argv[])
{
    pid_t pid ;
    pid = fork();
    if (pid < 0)
    {
        perror("fork") ;
        exit(-1) ;
    }
    else if(pid == 0)  //child1
    {
        signal(SIGINT,sighandler_child) ; //售票員接收訊號
        signal(SIGQUIT,sighandler_child) ; //售票員接收訊號
        signal(SIGTSTP,SIG_IGN) ; //售票員忽略到站
        signal(SIGUSR1,sighandler_child) ;
        while(1) ;
    }
    else //parent 
    {
        pid_child = pid ;
        signal(SIGINT,SIG_IGN) ; //忽略Ctrl + c
        signal(SIGUSR1,sighandler_parent) ;
        signal(SIGQUIT,SIG_IGN) ; //忽略Ctrl + '\'
        signal(SIGUSR2,sighandler_parent) ;
        signal(SIGTSTP,sighandler_parent) ; //到站 Ctrl + z
        waitpid(pid_child,NULL,0) ;
    }
    return 0 ;
}

總結:linux通訊機制中訊號與訊號燈是兩種通訊方式, System V的訊號燈又被稱為訊號量,是不同程序間或一個給定程序內部不同執行緒間同步的機制。