1. 程式人生 > >Linux訊號(一)——子程序的非同步等待方式

Linux訊號(一)——子程序的非同步等待方式

1.訊號

   訊號(是一種軟體中斷)是由使用者、系統或者程序傳送給目標程序的資訊,以通知目標程序某個狀態的改變或系統異常。

2.訊號的產生

(1)前臺程序,使用者可以通過輸入特殊終端字元來給它傳送訊號。比如Ctrl+C通常給程序傳送一箇中斷訊號——2號訊號(SIGINT),只能終止前臺程序(後臺程序一般在執行後面加&,就可以使得程序在後臺執行)。 (2)系統異常。比如浮點異常——8號訊號(SIGFPE)。 (3)系統狀態變化。比如alarm函式定時器到期引起14號訊號——SIGALRM訊號。 (4)執行kill命令呼叫kill函式。產生9號訊號——SIGKILL(該訊號不能被定義或捕捉,該訊號用來殺死程序)。

3.訊號的分類

列表中,編號為1~31號訊號為普通訊號,也稱為不可靠訊號;編號34~64為後來擴充的,被稱作可靠 訊號(實時訊號);不可靠訊號和可靠訊號二者的區別是前者不支援排隊,可能會造成訊號丟失, 後者不會。

4.Linux訊號處理方式

(1)忽略此訊號。大多數訊號都可以使用這種方式進行處理,除了9)SIGKILL和19)SIGSTOP。這兩種訊號不能被忽略的原因:它們是用來終止程序的一種可靠的方法。如果忽略某些由硬體異常所產生的訊號(例如非法儲存訪問或除以0),則程序的行為是未定義的。 (2)執行預設動作(大部分的預設動作就是終止該程序(Term)),還有比如:忽略訊號(Ign)、結束程序並生成核心轉儲檔案(Core)、暫停程序(Stop)、以及繼續程序(Cont)。
(3)捕捉訊號。提供一個自定義的動作。

5.訊號相關函式

(1)signal函式
#include<signal.h>
void(*signal (int signo ,void (*func)(int))) (int);

           //返回則為以前的訊號處理配置,若出錯則為SIG_ERR
signo引數是上圖的訊號名。 func的值為: 如果指定為常數SIG_IGN,代表核心忽略此訊號(SIGKILL和SIGSTOP不能忽略) ; 如果指定為常數SIG_DFL,代表接到此訊號之後執行系統預設動作 如果指定為函式地址時,我們稱捕捉此訊號。  (2)kill和raise函式
#include <sys/types.h>
#include <signal.h>

int kill (pid_t pid, int signo);

int raise(int signo);

                  //兩個函式返回:成功則為0,若出錯則為-1

kill命令呼叫kill函式實現,kill函式給一個指定的程序傳送指定的訊號 raise函式只允許程序向自身傳送訊號

6.驗證子程序退出會給父程序傳送訊號

測試程式碼:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <error.h>
void catchsignal(int sig)
{
    printf("I am a father my pid is:%d , receive signal is %d\n",getpid(),sig);
}
int main()
{
    signal(SIGCHLD,catchsignal);
    pid_t id=fork();
    if(id==0){
        //child
       int count=0;
       while(count<4){
           printf("I am a child,my pid is: %d ,my father's pid is: %d \n",getpid(),getppid());
           sleep(1);
           count++;
       }   
       exit(0);
    }
    else if(id>0){
        //father
        waitpid(id,NULL,0);
    }
    else{
        perror("fork error\n");
    }

    return 0;
}

執行結果:
很明顯子程序退出時父程序收到了17號訊號——17)SIGCHLD。

7.編寫父程序等待子程序的非同步版本

非同步:父子程序互不干擾(非阻塞式等待),繼續執行各自任務。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <error.h>
void catchsignal(int sig)
{
    printf("I am a father my pid is:%d , receive signal is %d\n",getpid(),sig);
}
int main()
{
    signal(SIGCHLD,catchsignal);
    pid_t id=fork();
    if(id==0){
        //child
       int count=0;
       while(count<4){
           printf("I am a child,my pid is: %d ,my father's pid is: %d \n",getpid(),getppid());
           sleep(1);
           count++;
       }   
       exit(0);
    }
    else if(id>0){
        //father
        while(1){
            sleep(2);
            printf("I am a father,running\n");
        }
    }
    else{
        perror("fork error\n");
    }

    return 0;
}

執行結果: