1. gzyueqian
      13352868059
      首頁 > 新聞中心 > > 正文

      Linux后端服務程序之信號處理

      更新時間: 2012-06-04 09:46:46來源: 粵嵌教育瀏覽量:3850

        信號就是通知某個進程發了某個事件,也稱為軟件中斷。信號提供了一種處理異步事件的方法。信號通常是異步發生的,進程預先不知道信號準確發生的時刻。后端程序(daemon)往往需要提供7*24不間斷的服務,因此,編程 daemon 程序時對信號的正確處理尤為重要。

        下面和大家分享編寫 daemon 程序時信號處理的注意事項,內容都來自 Internet,只是進行了整理和總結。關于信號的基礎只是請參考 APUE。

        常見的信號

        SIGHUP 1 和終端的連接斷開,發送該信號給控制進程。通常用此信號來通知 daemon 重新讀取配置文件(因為 daemon 不會有控制終端,通常不會收到該信號)。

        SIGINT 2 用戶中斷(Ctrl + C)。

        SIGABRT 6 調用 abort 函數產生(通常是自殺)。

        SIGKILL 9 可以殺死任意進程,不能被捕獲或忽略(俗稱酒殺)。

        SIGSEGV 11 無效的內存引用(segmentation fault)。

        SIGPIPE 13 對于 socket fd,當一個進程向某個已經收到 RST 的 fd 執行寫操作時,內核會向該進程發送該信號。

        SIGTERM 15 kill 命令發送的默認終止信號。

        SIGCHLD 17 進程終止時向其父進程發送的信號。

        SIGPROF 27 使用 gprof 工具測試時會收到該信號。

        別用 signal,用 sigaction

        可以通過 signal 或者 sigaction 函數來設置信號處理函數,但 signal 函數太過古老,因此推薦使用 sigaction。理由如下:

        1. sigaction 可以提供更多接收到信號的信息。

        2. 調用完信號處理函數后重新設置處理函數不會對 sigaction 有影響,因為 sigaction 默認是不會去重置處理函數的,同時在執行處理函數會屏蔽掉該信號,也不會有競爭。

        3. signal 函數在某些系統中會默認重啟被中斷的系統調用,而 sigaction 默認不會這樣做。

        4. signal 函數在多線程環境中的行為是未定義的,必須使用 sigaction 函數。

        數據傳輸和信號

        使用了系統調用的函數都有可能被信號中斷,立刻返回的函數(不需要等待I/O操作的完成或 sleep)不會被中斷,而需要等待的函數(等待網絡傳輸,管道的讀或者 sleep)將會被中斷,比如 select, read, connect。

        在 daemon 程序中,恰當地處理被中斷的系統調用是非常重要的。如果 read, write 等傳輸數據的函數被中斷,必須處理這種情況并恢復數據的傳輸。有兩種被中斷的場景:

        1. 當沒有數據傳輸時就被中斷,函數返回-1,這時可以通過判斷 errno 的值來識別這種錯誤,如果 errno == EINTR,則表示函數在沒有任何數據傳輸的情況下就被中斷,這時可以通過同樣的參數來再次調用該數據。

        2. 另一種情況是數據傳輸已經在進行,但在沒有完成之前被中斷;這種情況下函數不會返回錯誤,而是返回一個小于期望大小的值,同時 errno 也不會有錯誤設置,想識別這種情況只能捕獲導致中斷的信號。在中斷之后恢復數據傳輸時一定記得部分數據已經被傳輸,必須從正確的偏移再次發起傳輸。

        不要通過 sigaction 函數設置 SA_RESTART 來處理被中斷的系統調用。

        多線程和信號

        多線程程序的信號處理和單線程程序有很大的區別。根據 POSIX 規范,一個多線程的程序只有一個進程和一個 pid,哪個線程會被中斷并處理到達的信號呢?有兩種情況:

        發送給進程的信號比如用 kill 向一個 pid 發送信號,每個線程都有單獨的信號掩碼,可以通過 pthread_sigmask 來設置。信號不會分發給已經屏蔽了該信號的線程,而是在沒有屏蔽該信號的線程中任選一個來接收,但沒有指定哪個線程一定可以接收到。如果所有的線程都屏蔽了該信號,該信號將在預處理隊列中排隊。

        發送給線程的信號 pthread_kill 可以用來向指定的線程發送信號,分發和排隊都是線程級別的。如果沒有指定信號處理函數,而默認是結束進程,發送給線程的信號也會導致整個進程退出。

        不要在信號處理函數中使用鎖。

        同步化信號處理 signalfd

        signalfd 是一個在 linux kernel 2.6.22 提供的系統調用,功能是使用一個 fd 來接收信號。這樣就可以同步地處理信號,也不需要設置處理函數??梢?man signalfd 查看示例程序。首先必須使用 sigprocmask 來屏蔽要使用 signalfd 來處理的信號,然后調用 signalfd 創建一個 fd 用來讀取到達的信號。當被屏蔽的信號到達時,程序將不會被中斷,也不會有處理函數被調用。信號會在 fd 中排隊。signalfd 創建的 fd 可以和其他 fd 一樣:可以放在 select, poll, epoll 中;可以設置為非阻塞;可以為不同的信號創建不同的 fd;在 fork 之后該 fd 也不會關閉掉,子進程同樣可以讀懂發送給父進程的信號。signalfd 非常適合在主循環中執行 epoll 處理大量連接的單進程網絡服務程序中使用,信號的處理可以和其他 fd 一樣加到 epoll 中。由于程序不會被中斷,可以選擇合適的時機才去處理信號。

      免費預約試聽課

      亚洲另类欧美综合久久图片区_亚洲中文字幕日产无码2020_欧美日本一区二区三区桃色视频_亚洲AⅤ天堂一区二区三区

      
      

      1. 香蕉影视在线观看播放 | 日韩专区国产99 | 亚洲精品国产福利一二区 | 亚洲区精品久久一区二区三区 | 一本国产在线视频 | 色影音先锋国产资源 |