久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Linux信號處理機(jī)制

 天空上的極限 2016-08-04

在Linux中,信號是進(jìn)程間通訊的一種方式,,它采用的是異步機(jī)制。當(dāng)信號發(fā)送到某個(gè)進(jìn)程中時(shí),,操作系統(tǒng)會(huì)中斷該進(jìn)程的正常流程,,并進(jìn)入相應(yīng)的信號處理函數(shù)執(zhí)行操作,完成后再回到中斷的地方繼續(xù)執(zhí)行,。

需要說明的是,,信號只是用于通知進(jìn)程發(fā)生了某個(gè)事件,除了信號本身的信息之外,,并不具備傳遞用戶數(shù)據(jù)的功能,。

1 信號的響應(yīng)動(dòng)作

每個(gè)信號都有自己的響應(yīng)動(dòng)作,當(dāng)接收到信號時(shí),,進(jìn)程會(huì)根據(jù)信號的響應(yīng)動(dòng)作執(zhí)行相應(yīng)的操作,,信號的響應(yīng)動(dòng)作有以下幾種:

  • 中止進(jìn)程(Term)
  • 忽略信號(Ign)
  • 中止進(jìn)程并保存內(nèi)存信息(Core)
  • 停止進(jìn)程(Stop)
  • 繼續(xù)運(yùn)行進(jìn)程(Cont)

用戶可以通過signalsigaction函數(shù)修改信號的響應(yīng)動(dòng)作(也就是常說的“注冊信號”,在文章的后面會(huì)舉例說明),。另外,,在多線程中,,各線程的信號響應(yīng)動(dòng)作都是相同的,不能對某個(gè)線程設(shè)置獨(dú)立的響應(yīng)動(dòng)作,。

2 信號類型

Linux支持的信號類型可以參考下面給出的列表,。

2.1 在POSIX.1-1990標(biāo)準(zhǔn)中的信號列表

信號 動(dòng)作 說明
SIGHUP 1 Term 終端控制進(jìn)程結(jié)束(終端連接斷開)
SIGINT 2 Term 用戶發(fā)送INTR字符(Ctrl+C)觸發(fā)
SIGQUIT 3 Core 用戶發(fā)送QUIT字符(Ctrl+/)觸發(fā)
SIGILL 4 Core 非法指令(程序錯(cuò)誤、試圖執(zhí)行數(shù)據(jù)段,、棧溢出等)
SIGABRT 6 Core 調(diào)用abort函數(shù)觸發(fā)
SIGFPE 8 Core 算術(shù)運(yùn)行錯(cuò)誤(浮點(diǎn)運(yùn)算錯(cuò)誤,、除數(shù)為零等)
SIGKILL 9 Term 無條件結(jié)束程序(不能被捕獲、阻塞或忽略)
SIGSEGV 11 Core 無效內(nèi)存引用(試圖訪問不屬于自己的內(nèi)存空間,、對只讀內(nèi)存空間進(jìn)行寫操作)
SIGPIPE 13 Term 消息管道損壞(FIFO/Socket通信時(shí),,管道未打開而進(jìn)行寫操作)
SIGALRM 14 Term 時(shí)鐘定時(shí)信號
SIGTERM 15 Term 結(jié)束程序(可以被捕獲、阻塞或忽略)
SIGUSR1 30,10,16 Term 用戶保留
SIGUSR2 31,12,17 Term 用戶保留
SIGCHLD 20,17,18 Ign 子進(jìn)程結(jié)束(由父進(jìn)程接收)
SIGCONT 19,18,25 Cont 繼續(xù)執(zhí)行已經(jīng)停止的進(jìn)程(不能被阻塞)
SIGSTOP 17,19,23 Stop 停止進(jìn)程(不能被捕獲,、阻塞或忽略)
SIGTSTP 18,20,24 Stop 停止進(jìn)程(可以被捕獲,、阻塞或忽略)
SIGTTIN 21,21,26 Stop 后臺(tái)程序從終端中讀取數(shù)據(jù)時(shí)觸發(fā)
SIGTTOU 22,22,27 Stop 后臺(tái)程序向終端中寫數(shù)據(jù)時(shí)觸發(fā)

:其中SIGKILLSIGSTOP信號不能被捕獲、阻塞或忽略,。

2.2 在SUSv2和POSIX.1-2001標(biāo)準(zhǔn)中的信號列表

信號 動(dòng)作 說明
SIGTRAP 5 Core Trap指令觸發(fā)(如斷點(diǎn),,在調(diào)試器中使用)
SIGBUS 0,7,10 Core 非法地址(內(nèi)存地址對齊錯(cuò)誤)
SIGPOLL Term Pollable event (Sys V). Synonym for SIGIO
SIGPROF 27,27,29 Term 性能時(shí)鐘信號(包含系統(tǒng)調(diào)用時(shí)間和進(jìn)程占用CPU的時(shí)間)
SIGSYS 12,31,12 Core 無效的系統(tǒng)調(diào)用(SVr4)
SIGURG 16,23,21 Ign 有緊急數(shù)據(jù)到達(dá)Socket(4.2BSD)
SIGVTALRM 26,26,28 Term 虛擬時(shí)鐘信號(進(jìn)程占用CPU的時(shí)間)(4.2BSD)
SIGXCPU 24,24,30 Core 超過CPU時(shí)間資源限制(4.2BSD)
SIGXFSZ 25,25,31 Core 超過文件大小資源限制(4.2BSD)

:在Linux 2.2版本之前,SIGSYS,、SIGXCPU,、SIGXFSZ以及SIGBUS的默認(rèn)響應(yīng)動(dòng)作為Term,Linux 2.4版本之后這三個(gè)信號的默認(rèn)響應(yīng)動(dòng)作改為Core,。

2.3 其它信號

信號 動(dòng)作 說明
SIGIOT 6 Core IOT捕獲信號(同SIGABRT信號)
SIGEMT 7,-,7 Term 實(shí)時(shí)硬件發(fā)生錯(cuò)誤
SIGSTKFLT -,16,- Term 協(xié)同處理器棧錯(cuò)誤(未使用)
SIGIO 23,29,22 Term 文件描述符準(zhǔn)備就緒(可以開始進(jìn)行輸入/輸出操作)(4.2BSD)
SIGCLD -,-,18 Ign 子進(jìn)程結(jié)束(由父進(jìn)程接收)(同SIGCHLD信號)
SIGPWR 29,30,19 Term 電源錯(cuò)誤(System V)
SIGINFO 29,-,- 電源錯(cuò)誤(同SIGPWR信號)
SIGLOST -,-,- Term 文件鎖丟失(未使用)
SIGWINCH 28,28,20 Ign 窗口大小改變時(shí)觸發(fā)(4.3BSD, Sun)
SIGUNUSED -,31,- Core 無效的系統(tǒng)調(diào)用(同SIGSYS信號)

注意:列表中有的信號有三個(gè)值,,這是因?yàn)椴糠中盘柕闹岛虲PU架構(gòu)有關(guān),這些信號的值在不同架構(gòu)的CPU中是不同的,,三個(gè)值的排列順序?yàn)椋?,,Alpha/Sparc;2,,x86/ARM/Others,;3,MIPS,。

例如SIGSTOP這個(gè)信號,,它有三種可能的值,分別是17,、19,、23,其中第一個(gè)值(17)是用在Alpha和Sparc架構(gòu)中,,第二個(gè)值(19)用在x86,、ARM等其它架構(gòu)中,第三個(gè)值(23)則是用在MIPS架構(gòu)中的,。

3 信號機(jī)制

文章的前面提到過,,信號是異步的,,這就涉及信號何時(shí)接收、何時(shí)處理的問題,。

我們知道,,函數(shù)運(yùn)行在用戶態(tài),當(dāng)遇到系統(tǒng)調(diào)用,、中斷或是異常的情況時(shí),,程序會(huì)進(jìn)入內(nèi)核態(tài)。信號涉及到了這兩種狀態(tài)之間的轉(zhuǎn)換,,過程可以先看一下下面的示意圖:

信號處理機(jī)制示意圖

接下來圍繞示意圖,,將信號分成接收、檢測和處理三個(gè)部分,,逐一講解每一步的處理流程,。

3.1 信號的接收

接收信號的任務(wù)是由內(nèi)核代理的,當(dāng)內(nèi)核接收到信號后,,會(huì)將其放到對應(yīng)進(jìn)程的信號隊(duì)列中,,同時(shí)向進(jìn)程發(fā)送一個(gè)中斷,使其陷入內(nèi)核態(tài),。

注意,,此時(shí)信號還只是在隊(duì)列中,對進(jìn)程來說暫時(shí)是不知道有信號到來的,。

3.2 信號的檢測

進(jìn)程陷入內(nèi)核態(tài)后,,有兩種場景會(huì)對信號進(jìn)行檢測:

  • 進(jìn)程從內(nèi)核態(tài)返回到用戶態(tài)前進(jìn)行信號檢測
  • 進(jìn)程在內(nèi)核態(tài)中,從睡眠狀態(tài)被喚醒的時(shí)候進(jìn)行信號檢測

當(dāng)發(fā)現(xiàn)有新信號時(shí),,便會(huì)進(jìn)入下一步,,信號的處理。

3.3 信號的處理

信號處理函數(shù)是運(yùn)行在用戶態(tài)的,,調(diào)用處理函數(shù)前,,內(nèi)核會(huì)將當(dāng)前內(nèi)核棧的內(nèi)容備份拷貝到用戶棧上,并且修改指令寄存器(eip)將其指向信號處理函數(shù),。

接下來進(jìn)程返回到用戶態(tài)中,執(zhí)行相應(yīng)的信號處理函數(shù),。

信號處理函數(shù)執(zhí)行完成后,,還需要返回內(nèi)核態(tài),檢查是否還有其它信號未處理,。如果所有信號都處理完成,,就會(huì)將內(nèi)核棧恢復(fù)(從用戶棧的備份拷貝回來),,同時(shí)恢復(fù)指令寄存器(eip)將其指向中斷前的運(yùn)行位置,,最后回到用戶態(tài)繼續(xù)執(zhí)行進(jìn)程,。

至此,一個(gè)完整的信號處理流程便結(jié)束了,,如果同時(shí)有多個(gè)信號到達(dá),,上面的處理流程會(huì)在第2步和第3步驟間重復(fù)進(jìn)行。

4 信號的使用

4.1 發(fā)送信號

用于發(fā)送信號的函數(shù)有raise,、kill,、killpgpthread_kill,、tgkill,、sigqueue,這幾個(gè)函數(shù)的含義和用法都大同小異,,這里主要介紹一下常用的raisekill函數(shù),。

raise函數(shù):向進(jìn)程本身發(fā)送信號

函數(shù)聲明如下:

#include <signal.h>

int raise(int sig);

函數(shù)功能是向當(dāng)前程序(自身)發(fā)送信號,其中參數(shù)sig為信號值,。

kill函數(shù):向指定進(jìn)程發(fā)送信號

函數(shù)聲明如下:

#include <sys/types.h>
#include <signal.h>

int kill(pid_t pid, int sig);

函數(shù)功能是向特定的進(jìn)程發(fā)送信號,,其中參數(shù)pid為進(jìn)程號,sig為信號值,。

在這里的參數(shù)pid,,根據(jù)取值范圍不同,含義也不同,,具體說明如下:

  • pid > 0 :向進(jìn)程號為pid的進(jìn)程發(fā)送信號
  • pid = 0 :向當(dāng)前進(jìn)程所在的進(jìn)程組發(fā)送信號
  • pid = -1 :向所有進(jìn)程(除PID=1外)發(fā)送信號(權(quán)限范圍內(nèi))
  • pid < -1 :向進(jìn)程組號為-pid的所有進(jìn)程發(fā)送信號

另外,,當(dāng)sig值為零時(shí),實(shí)際不發(fā)送任何信號,,但函數(shù)返回值依然有效,,可以用于檢查進(jìn)程是否存在。

4.2 等待信號被捕獲

等待信號的過程,,其實(shí)就是將當(dāng)前進(jìn)程(線程)暫停,,直到有信號發(fā)到當(dāng)前進(jìn)程(線程)上并被捕獲,函數(shù)有pausesigsuspend,。

pause函數(shù):將進(jìn)程(或線程)轉(zhuǎn)入睡眠狀態(tài),,直到接收到信號

函數(shù)聲明如下:

#include <unistd.h>

int pause(void);

該函數(shù)調(diào)用后,調(diào)用者(進(jìn)程或線程)會(huì)進(jìn)入睡眠(Sleep)狀態(tài),,直到捕獲到(任意)信號為止,。該函數(shù)的返回值始終為-1,并且調(diào)用結(jié)束后,,錯(cuò)誤代碼(errno)會(huì)被置為EINTR,。

sigsuspend函數(shù):將進(jìn)程(或線程)轉(zhuǎn)入睡眠狀態(tài),直到接收到特定信號

函數(shù)聲明如下:

#include <signal.h>

int sigsuspend(const sigset_t *mask);

該函數(shù)調(diào)用后,,會(huì)將進(jìn)程的信號掩碼臨時(shí)修改(參數(shù)mask),,然后暫停進(jìn)程,,直到收到符合條件的信號為止,函數(shù)返回前會(huì)將調(diào)用前的信號掩碼恢復(fù),。該函數(shù)的返回值始終為-1,,并且調(diào)用結(jié)束后,錯(cuò)誤代碼(errno)會(huì)被置為EINTR,。

4.3 修改信號的響應(yīng)動(dòng)作

用戶可以自己重新定義某個(gè)信號的處理方式,,即前面提到的修改信號的默認(rèn)響應(yīng)動(dòng)作,也可以理解為對信號的注冊,,可以通過signalsigaction函數(shù)進(jìn)行,,這里以signal函數(shù)舉例說明。

首先看一下函數(shù)聲明:

#include <signal.h>

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);

第一個(gè)參數(shù)signum是信號值,,可以從前面的信號列表中查到,,第二個(gè)參數(shù)handler為處理函數(shù),通過回調(diào)方式在信號觸發(fā)時(shí)調(diào)用,。

下面為示例代碼:

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

/* 信號處理函數(shù) */
void sig_callback(int signum) {
    switch (signum) {
        case SIGINT:
            /* SIGINT: Ctrl+C 按下時(shí)觸發(fā) */
            printf("Get signal SIGINT. \r\n");
            break;
        /* 多個(gè)信號可以放到同一個(gè)函數(shù)中進(jìn)行 通過信號值來區(qū)分 */
        default:
            /* 其它信號 */
            printf("Unknown signal %d. \r\n", signum);
            break;
    }

    return;
}

/* 主函數(shù) */
int main(int argc, char *argv[]) {
    printf("Register SIGINT(%u) Signal Action. \r\n", SIGINT);

    /* 注冊SIGINT信號的處理函數(shù) */
    signal(SIGINT, sig_callback);

    printf("Waitting for Signal ... \r\n");

    /* 等待信號觸發(fā) */
    pause();

    printf("Process Continue. \r\n");

    return 0;
}

源文件下載:鏈接

例子中,,將SIGINT信號(Ctrl+C觸發(fā))的動(dòng)作接管(打印提示信息),程序運(yùn)行后,,按下Ctrl+C,,命令行輸出如下:

./linux_signal_example
Register SIGINT(2) Signal Action. 
Waitting for Signal ... 
^CGet signal SIGINT. 
Process Continue.

進(jìn)程收到SIGINT信號后,觸發(fā)響應(yīng)動(dòng)作,,將提示信息打印出來,,然后從暫停的地方繼續(xù)運(yùn)行。這里需要注意的是,,因?yàn)槲覀冃薷牧?code>SIGINT信號的響應(yīng)動(dòng)作(只打印信息,,不做進(jìn)程退出處理),所以我們按下Ctrl+C后,,程序并沒有直接退出,,而是繼續(xù)運(yùn)行并將"Process Continue."打印出來,直至程序正常結(jié)束,。

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn),。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多