Python和Signal

來源:互聯網
上載者:User

標籤:sigabrt   不同的   sighup   socket   不同   用途   main   receive   blank   

 

先簡單說一下Signal是啥.(如果想直接使用可以不看)

Signal翻譯過來中文就是訊號- -
當然, 本身他就是Linux系統編程中非常重要的概念, 訊號機制是進程之間傳遞訊息的一種機制,

其全稱為非強制中斷訊號
作用是通知進程發生了非同步事件。進程之間可以調用系統來傳遞訊號, 本身核心也可以發送訊號給進程, 告訴該進程發生了某個事件.

注意,訊號只是用來通知某進程發生了什麼事件,並不給該進程傳遞任何資料。

接收訊號的進程對不同的訊號有三種處理方法

  1. 指定處理函數
  2. 忽略
  3. 根據系統預設值處理, 大部分訊號的預設處理是終止進程

然後就是一大段類型了..
Linux系統有兩大類訊號

  1. POSIX標準的規則訊號(regular signal 1-31編號)
  2. 即時訊號(real-time signal 32-63)
規則訊號
訊號編號 名稱 預設動作 說明
1 SIGHUP 終止 終止控制終端或進程
2 SIGINT 終止 由鍵盤引起的終端(Ctrl-c)
3 SIGQUIT dump 控制終端發送給進程的訊號, 鍵盤產生的退出(Ctrl-\),
4 GIGILL dusmp 非法指令引起
5 SIGTRAP dump debug中斷
6 SIGABRT/SIGIOT dump 異常中止
7 SIGBUS/SIGEMT dump 匯流排異常/EMT指令
8 SIGFPE dump 浮點運算溢出
9 SIGKILL 終止 強制殺死進程(大招, 進程不可捕獲)
10 SIGUSR1 終止 使用者訊號, 進程可自訂用途
11 SIGSEGV dump 非法記憶體位址引起
12 SIGUSR2 終止 使用者訊號, 進程可自訂用途
13 SIGPIPE 終止 向某個沒有讀取的管道中寫入資料
14 SIGALRM 終止 時鐘中斷(鬧鐘)
15 SIGTERM 終止 進程終止(進程可捕獲)
16 SIGSTKFLT 終止 副處理器棧錯誤
17 SIGCHLD 忽略 子進程退出或中斷
18 SIGCONT 繼續 如進程停止狀態則開始運行
19 SIGSTOP 停止 停止進程運行
20 SIGSTP 停止 鍵盤產生的停止
21 SIGTTIN 停止 後台進程請求輸入
22 SIGTTOU 停止 後台進程請求輸出
23 SIGURG 忽略 socket發送緊急情況
24 SIGXCPU dump CPU時間限制被打破
25 SIGXFSZ dump 檔案大小限制被打破
26 SIGVTALRM 終止 虛擬定時時鐘
27 SIGPROF 終止 profile timer clock
28 SIGWINCH 忽略 視窗尺寸調整
29 SIGIO/SIGPOLL 終止 I/O可用
30 SIGPWR 終止 電源異常
31 SIGSYS/SYSUNUSED dump 系統調用異常

注意: 由於不同系統中同一個數值對應的訊號類型不一樣, 所以最好使用訊號名稱.
訊號的數值越小, 優先順序越高.

OK, 現在來說說Python中的處理

先列幾個常用的訊號:

編號 訊號名稱 說明
2 SIGINT 當按下鍵盤(Ctrl-c)按鍵組合時進程就會收到這個訊號
15 SIGTERM 當使用者輸入 kill sigterm pid. 對應的進程就會收到這個訊號. 這個訊號進程是可以捕獲並指定函數處理, 例如做一下程式清理等工作. 甚至忽視這個訊號
9 SIGKILL 強制殺死進程, 這個訊號進程無法忽視, 直接在系統層面把進程殺掉. 所以在Python中他的不能監聽的
14 SIGALRM 鬧鐘訊號
去碼

先來一個例子

#!/usr/bin/env python# -*- coding: utf-8 -*-"""    監聽了SIGINT訊號, 當程式在啟動並執行時候同步選取鍵盤 Ctrl+c 就會輸出    收到訊號 2 <frame object at 0x00000000021DD048>    handler方法的兩個參數分別是 訊號編號, 程式幀"""import sysreload(sys)sys.setdefaultencoding("utf-8")import timeimport osimport signalreceive_times = 0def handler(signalnum, handler):    global receive_times    print u"收到訊號", signalnum, frame, receive_times    receive_times += 1    if receive_times > 3:        exit(0) # 自己走def main():    signal.signal(signal.SIGINT, handler) # Ctrl-c    # time.sleep(10) # SIGINT 訊號同樣能喚醒 time.sleep, 所以這裡程式就會結束    while True: # 改成 while 效果會好點       passif __name__ == ‘__main__‘:    main()

再看看SIGTERM的效果

#!/usr/bin/env python# -*- coding: utf-8 -*-"""    當我們運行該程式時因為 while True 所以會持續的運行.     這裡監聽的是 SIGTERM 訊號, 所以當我們在終端輸入 kill pid (linux kill    預設是發送SIGTERM)時,     程式就會輸出: 收到訊號 15 <frame object at 0x7ff695738050> 0    當超過3次時就強制把自己殺死.    所以 SIGTERM 很適合用來做一些清理的工作"""import sysreload(sys)sys.setdefaultencoding("utf-8")import timeimport osimport signalreceive_times = 0def handler(signalnum, frame):    global receive_times    print u"收到訊號", signalnum, frame, receive_times    receive_times += 1    if receive_times > 3:        exit(0) # 自己走def main():    print "pid:", os.getpid()    signal.signal(signal.SIGTERM, handler)    while True:        passif __name__ == ‘__main__‘:    main()

剛才我們說過SIGKILL不能被監聽.

signal.signal(signal.SIGKILL, handler) # 這裡系統會直接跑錯 AttributeError: ‘module‘ object has no attribute ‘SIGKILL‘
最後來一個實際運用的例子

在python2.x的版本, 線程有個bug, 在join的時候不能接收訊號
詳解見:https://bugs.python.org/issue1167930
所以如果我們運行以下代碼

#!/usr/bin/env python# -*- coding: utf-8 -*-"""    這裡雖然我們監聽了 SIGINT 訊號, 但是當我們按下Ctrl-c時程式並沒有任何輸出. 還是要等線程運行完成程式才退出."""import sysreload(sys)sys.setdefaultencoding("utf-8")import timeimport osimport signalimport threadingreceive_times = 0def handler(signalnum, frame):    global receive_times    print u"收到訊號", signalnum, frame, receive_times    receive_times += 1    if receive_times > 3:        # os.kill(os.getpid(), signal.SIGTERM) # 我瘋起來連自己都殺        exit(0)def run():    print "thread %s run:"%(threading.currentThread().getName())    time.sleep(10)    print "thread %s done"%(threading.currentThread().getName())def main():    print "pid:", os.getpid()    signal.signal(signal.SIGINT, handler)    thread_list = []    for i in range(5):        thread = threading.Thread(target = run)        thread_list.append(thread)    for thread in thread_list:        thread.start()    for thread in thread_list:        thread.join()    print "all thread done"if __name__ == ‘__main__‘:    main()

然後我們來改一下

#!/usr/bin/env python# -*- coding: utf-8 -*-"""    在這裡我們放棄了線程的join() 方法, 然後用 while True 的方式來代替, 然後在主進程判斷線程的存活狀態. 這樣既能持續的運行線程又能根據需求來隨時中斷"""import sysreload(sys)sys.setdefaultencoding("utf-8")import timeimport osimport signalimport threadingis_run_thread = Truedef handler(signalnum, frame):    print u"收到訊號", signalnum, frame    global is_run_thread    is_run_thread = False # 停止運行線程def run():    print "thread %s run:"%(threading.currentThread().getName())    while is_run_thread:        # do something        pass    print "thread %s done"%(threading.currentThread().getName())def main():    print "pid:", os.getpid()    signal.signal(signal.SIGINT, handler)    thread_list = []    for i in range(5):        thread = threading.Thread(target = run)        thread_list.append(thread)    for thread in thread_list:        thread.start()   # 注意這裡    while True:        for thread in thread_list:            if thread.isAlive():                break        else:            break    # for thread in thread_list:    #     thread.join()    print "all thread done"if __name__ == ‘__main__‘:    main()

注意, 在wnidows系統中只能調用 SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, or SIGTERM

Python和Signal

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.