【Linux】進程信號

一、首先,用 kill -l 命令可以查看系統定義的信號列表:
這裏寫圖片描述
每個信號都有一個編號和一個宏定義名稱,這些宏定義可以在 signal.h 中查看,例如:#define SIGINT 2 。編號34以上的信號爲實時信號。

二、信號常見的三種處理方式:

(1)忽略此信號。(SIG_IGN)
(2)執行信號的默認處理動作。(SIG_DFL)
(3)提供一個信號處理函數,捕捉信號進行自定義處理。

三、信號的產生:

1、常見的幾種產生信號方式:

        a.用戶產生信號
        b.系統異常產生信號
        c.自定義捕捉

2、通過終端按鍵產生信號:

SIGINT的默認處理動作是終止進程,SIGQUIT的默認處理動作是終止進程,並且Core Dump

Core Dump (核心轉儲):當一個進程異常終止時,可以選擇把進程的用戶空間內存數據全部保存到磁盤上,文件名通常是Core,這叫做 Core Dump。


系統默認情況不予 Core 分配空間:
這裏寫圖片描述
可使用命令 ulimit -c 1024 給Core 分配 1024個字節空間:
這裏寫圖片描述
實例:寫一個死循環

[lize-h@localhost 0409_Siganl]$ cat core_Dump.c 
#include<stdio.h>

int main()
{
    printf("pid is %d\n",getpid());
    while(1);
    return 0;
}  

這裏寫圖片描述
3、調用系統函數向進程發信號:

(1)我們可以用 kill 命令向進程發信號:

[lize-h@localhost 0409_Siganl]$ ./a.out &     
[1] 3102
[lize-h@localhost 0409_Siganl]$ kill -SIGSEGV 3102
[lize-h@localhost 0409_Siganl]$ 
[1]+  段錯誤               (core dumped) ./a.out
[lize-h@localhost 0409_Siganl]$ cat core_Dump.c 
#include<stdio.h>
int main()
{
    //printf("pid is %d\n",getpid());
    while(1);
    return 0;
}

令程序在後臺執行,用 kill 命令向進程發送信號,令進程異常終止,異常信息存入core文件。

(2)發送信號的函數有:

#include<signal.h>

int kill(pid_t pid,int signo);  //向任意進程發送任意信號;成功返回0,出錯返回-1。
int raise(int signo);    //向自己發送任意信號;成功返回0,出錯返回-1。

#include<stdlib.h>

void abort(void);   //向自己發送 abort 信號

(3)alarm函數:

#include<unistd.h>

unsigned int alarm( unsigned int seconds);
/*
調用alarm函數可設置一個鬧鐘;當參數seconds設置爲0表示取消鬧鐘,返回值爲以前設置的
時間剩餘的秒數;當參數seconds設置爲8表示8秒後觸發鬧鐘,向當前進程發送SIGALRM信號,
該信號的默認處理動作是終止當前進程。
*/

四、阻塞信號

1、信號的相關概念:

(1)實際執行信號的處理動作稱爲信號遞達。
(2)信號從產生到遞達之間的狀態,稱爲信號未決(pending)。
(3)進程可以選擇阻塞(Block)某個信號。
(4)被阻塞的信號產生時將保持在未決狀態,直到信號解除對此信號的阻塞,才執行遞達的動作。
(5)阻塞和忽略不同,只要信號被阻塞就不會遞達,而忽略是在遞達後可選的一種處理動作。
(6)發送信號相當於更改PCB中的位圖

2、在內核中的表示:
這裏寫圖片描述
Linux信號的實現:常規信號在遞達之前產生多次只計一次,而實時信號在遞達之前產生多次可以依次放在一個隊列裏。

3、sigset_t 信號集:
未決和阻塞標誌可以用相同的數據類型sigset_t來存儲,sigset_t稱爲信號集,這個類型可以表示每個信號的“有效”或“無效”狀態,在阻塞信號集中“有效”和“無效”的含義是該信號是否被阻塞,而在未決信號集中“有效”和“無效”的含義是該信號是否處於未決狀態。阻塞信號集也叫做當前進程的信號屏蔽字(Signal Mask),這裏的“屏蔽”應該理解爲阻塞而不是忽略。

4、信號集操作函數:

#include<signal.h>

int sigemptyset(sigset_t* set); //初始化set所指向的信號集,使其中所有信號的對應bit清零。
int sigfillset(sigset_t* set);  //初始化set所指向的信號集,使其中所有信號的對應bit置1。
int sigaddset(sigset_t* set,int signo);  //在信號集中添加編號爲signo的信號
int sigdelset(sigset_t* set,int signo);  //刪除信號集中編號爲signo的信號
   //以上四個函數成功返回0,出錯返回-1。  
int sigismember(const sigset_t* set,int signo);  
//sigismember是一個布爾函數,用於判斷一個信號集的有效信號中是否包含某種信號,若包含則返回1,不包含返回0,出錯返回-1。


sigprocmask函數:

調用該函數可以讀取或更改進程的信號屏蔽字(阻塞信號集)

#include<signal.h>
int sigprocmask(int how,const sigset_t* set,sigset_t* oset);
//若調用成功返回0,出錯返回-1

如果oset爲空指針,則讀取進程的當前信號屏蔽字通過oset參數傳出。如果set是非空指針,則更改進程的信號屏蔽字,參數how指示如何更改。如果oset和set都是非空指針,則先將原來的信號屏蔽字備份到oset裏,然後根據set和how參數更改信號屏蔽字。假設當前的信號屏蔽字爲mask,以下爲how參數的可選值。
這裏寫圖片描述

sigpending函數:

#include<signal.h>
int sigpending(sigset_t* set)
//讀取當前進程的未決信號集,通過set參數傳出。調用成功返回0,出錯返回-1。

範例:

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

void printsigset(sigset_t *set)
{
    int i=0;
    for(;i<32;i++)
    {
        if(sigismember(set,i))
        {
            putchar('1');
        }
        else
        {
            putchar('0'); 
        }
    }
    puts("");
}
int main()
{
    sigset_t s,p;
    sigemptyset(&s);
    sigaddset(&s,SIGINT);
    gprocmask(SIG_BLOCK,&s,NULL);
    while(1)
    {
        sigpending(&p);
        printsigset(&p);
        sleep(1);
    }
    return 0;
}

運行結果:

[lize-h@localhost 0409_Siganl]$ ./a.out
10000000000000000000000000000000
10000000000000000000000000000000
10000000000000000000000000000000
10000000000000000000000000000000
10000000000000000000000000000000
^C10100000000000000000000000000000
10100000000000000000000000000000
10100000000000000000000000000000
10100000000000000000000000000000
^Z
[1]+  Stopped                 ./a.out
[lize-h@localhost 0409_Siganl]$ 

信號捕捉: https://mp.csdn.net/mdeditor/80044465

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章