乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Linux信號(hào)處理機(jī)制

       天空上的極限 2016-08-04

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

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

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

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

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

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

      2 信號(hào)類型

      Linux支持的信號(hào)類型可以參考下面給出的列表。

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

      信號(hào) 動(dòng)作 說(shuō)明
      SIGHUP 1 Term 終端控制進(jìn)程結(jié)束(終端連接斷開(kāi))
      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 無(wú)條件結(jié)束程序(不能被捕獲、阻塞或忽略)
      SIGSEGV 11 Core 無(wú)效內(nèi)存引用(試圖訪問(wèn)不屬于自己的內(nèi)存空間、對(duì)只讀內(nèi)存空間進(jìn)行寫操作)
      SIGPIPE 13 Term 消息管道損壞(FIFO/Socket通信時(shí),管道未打開(kāi)而進(jìn)行寫操作)
      SIGALRM 14 Term 時(shí)鐘定時(shí)信號(hào)
      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信號(hào)不能被捕獲、阻塞或忽略。

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

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

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

      2.3 其它信號(hào)

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

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

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

      3 信號(hào)機(jī)制

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

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

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

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

      3.1 信號(hào)的接收

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

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

      3.2 信號(hào)的檢測(cè)

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

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

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

      3.3 信號(hào)的處理

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

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

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

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

      4 信號(hào)的使用

      4.1 發(fā)送信號(hào)

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

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

      函數(shù)聲明如下:

      #include <signal.h>
      
      int raise(int sig);
      

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

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

      函數(shù)聲明如下:

      #include <sys/types.h>
      #include <signal.h>
      
      int kill(pid_t pid, int sig);
      

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

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

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

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

      4.2 等待信號(hào)被捕獲

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

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

      函數(shù)聲明如下:

      #include <unistd.h>
      
      int pause(void);
      

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

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

      函數(shù)聲明如下:

      #include <signal.h>
      
      int sigsuspend(const sigset_t *mask);
      

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

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

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

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

      #include <signal.h>
      
      typedef void (*sighandler_t)(int);
      
      sighandler_t signal(int signum, sighandler_t handler);
      

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

      下面為示例代碼:

      #include <stdio.h>
      #include <signal.h>
      #include <unistd.h>
      
      /* 信號(hào)處理函數(shù) */
      void sig_callback(int signum) {
          switch (signum) {
              case SIGINT:
                  /* SIGINT: Ctrl+C 按下時(shí)觸發(fā) */
                  printf("Get signal SIGINT. \r\n");
                  break;
              /* 多個(gè)信號(hào)可以放到同一個(gè)函數(shù)中進(jìn)行 通過(guò)信號(hào)值來(lái)區(qū)分 */
              default:
                  /* 其它信號(hào) */
                  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);
      
          /* 注冊(cè)SIGINT信號(hào)的處理函數(shù) */
          signal(SIGINT, sig_callback);
      
          printf("Waitting for Signal ... \r\n");
      
          /* 等待信號(hào)觸發(fā) */
          pause();
      
          printf("Process Continue. \r\n");
      
          return 0;
      }
      

      源文件下載:鏈接

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

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

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多