python signal

Python】簡單聊進程間異步通信之signal模塊

Linux


信號是Unix系統中常見的一種進程間通信方式(IPC),例如我們經常操作的 kill -9 pid 這裏的 -9對應的就是 SIGKILL 信號, 9就是這個信號的編號,SIGKILL是它的名稱。 由於不同版本的 *nux 的實現會有差異,具體請參照系統API,我這裏是OSX,可以使用 man signal查看所有信號的定義。這裏簡單的學習下Python標準庫中信號處理的模塊 signal模塊.

信號是啥?

由於signal是系統編程的接口,那麼咱們來看看他的概念。

信號(signal)是Linux進程間通信的一種機制,全稱爲軟中斷信號,也被稱爲軟中斷。信號本質上是在軟件層次上對硬件中斷機制的一種模擬。

再來看看常用的場景

與其他進程間通信方式(例如管道、共享內存等)相比,信號所能傳遞的信息比較粗糙,只是一個整數。但正是由於傳遞的信息量少,信號也便於管理和使用,可以用於系統管理相關的任務,例如通知進程終結、中止或者恢復等。每種信號用一個整型常量宏表示,以SIG開頭,比如SIGCHLD、SIGINT等,它們在系統頭文件中定義。

更具體的介紹和詳細的機制原理,請參考 《Unix環境高級編程》等書籍。

自己的理解就是:可以給一個正在運行的進程發送不同的信號,然後進程就能立即收到這個通知,並且做出響應的行爲。

常用的幾個信號

編號 名稱 作用
1 SIGHUP 終端掛起或者終止進程。默認動作爲終止進程
2 SIGINT 鍵盤中斷 <ctrl+c> 經常會用到。默認動作爲終止進程
3 SIGQUIT 鍵盤退出鍵被按下。一般用來響應 <ctrl+d>。 默認動作終止進程
9 SIGKILL 強制退出。 shell中經常使用
14 SIGALRM 定時器超時,默認爲終止進程
15 SIGTERM 程序結束信號,程序一般會清理完狀態在退出,我們一般說的優雅的退出

signal模塊

文檔的開頭,講述了Python signal對於系統的封裝和一些使用常識, 使用之前應當認真閱讀一下。

常用的API

  • signal.signal(signalnum, handler) 針對不同的信號需要定義對應的處理函數,當運行中的程序接受到對應的信號時候,會調用對應的handler。 handler函數應當有2個參數,一個是 signalnum, 另一是 stack frame(None 或者是 frame對象)

例如寫一個小程序,來處理 ctrl+c事件和 SIGHUP,也就是1和2信號。

  1. #coding:utf-8
  2. #orangleliu py2.7
  3. #recv_signal.py
  4. import signal
  5. import time
  6. import sys
  7. import os
  8. def handle_int(sig, frame):
  9. print "get signal: %s, I will quit"%sig
  10. sys.exit(0)
  11. def handle_hup(sig, frame):
  12. print "get signal: %s"%sig
  13. if __name__ == "__main__":
  14. signal.signal(2, handle_int)
  15. signal.signal(1, handle_hup)
  16. print "My pid is %s"%os.getpid()
  17. while True:
  18. time.sleep(3)

我們來測試下,首先啓動程序(根據打印的pid),在另外的窗口輸入 kill -1 21838 和 kill -HUP 21838, 最後使用 ctrl+c關閉程序。 程序的輸出如下:

  1. # python recv_signal.py
  2. My pid is 21838
  3. get signal: 1
  4. get signal: 1
  5. ^Cget signal: 2, I will quit
  • signal.getsignal(signalnum) 根據signalnum返回信號對應的handler,可能是一個可以調用的Python對象,或者是 signal.SIG_IGN(表示被忽略), signal.SIG_DFL(默認行爲已經被使用) 或 None(Python的handler還沒被定義)。

獲取signal中定義的信號num和名稱,還有它的handler是什麼

  1. #coding:utf-8
  2. #orangleliu py2.7
  3. #getsignal_handler.py
  4. import signal
  5. def handle_hup(sig, frame):
  6. print "get signal: %s"%sig
  7. signal.signal(1, handle_hup)
  8. if __name__ == "__main__":
  9. ign = signal.SIG_IGN
  10. dfl = signal.SIG_DFL
  11. print "SIG_IGN", ign
  12. print "SIG_DFL", dfl
  13. print "*"*40
  14. for name in dir(signal):
  15. if name[:3] == "SIG" and name[3] != "_":
  16. signum = getattr(signal, name)
  17. gsig = signal.getsignal(signum)
  18. print name, signum, gsig

運行的結果:可以看到大部分信號都是都有默認的行爲。

  1. SIG_IGN 1
  2. SIG_DFL 0
  3. ****************************************
  4. SIGABRT 6 0
  5. SIGALRM 14 0
  6. SIGBUS 10 0
  7. SIGCHLD 20 0
  8. SIGCONT 19 0
  9. SIGEMT 7 0
  10. SIGFPE 8 0
  11. SIGHUP 1 <function handle_hup at 0x109371c80>
  12. SIGILL 4 0
  13. SIGINFO 29 0
  14. SIGINT 2 <built-in function default_int_handler>
  15. SIGIO 23 0
  16. SIGIOT 6 0
  17. SIGKILL 9 None
  18. SIGPIPE 13 1
  19. SIGPROF 27 0
  20. SIGQUIT 3 0
  21. SIGSEGV 11 0
  22. SIGSTOP 17 None
  23. SIGSYS 12 0
  24. SIGTERM 15 0
  25. SIGTRAP 5 0
  26. SIGTSTP 18 0
  27. SIGTTIN 21 0
  28. SIGTTOU 22 0
  29. SIGURG 16 0
  30. SIGUSR1 30 0
  31. SIGUSR2 31 0
  32. SIGVTALRM 26 0
  33. SIGWINCH 28 0
  34. SIGXCPU 24 0
  35. SIGXFSZ 25 1
  • 多線程使用信號

參考

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