Python module - signal 處理教學

Posted on  Mar 9, 2018  in  Python 程式設計 - 高階  by  Amo Chen  ‐ 2 min read

Python 提供 signal 模組幫助處理 signal 相關事宜,例如按下 CTRL + C 時其實是對 python 程式送出一個 signal , signal 模組可以讓我們收到特定 signal 時進行處理。

為了感受 signal 實際作用,以下先實作一個按下 CTRL + C 時會先列印 Good Bye 再結束的 python 程式:

# -*- encoding: utf-8 -*-
import signal
from time import sleep


def say_good_bye(signum, frame):
    print()
    print('Good Bye')
    print()
    raise KeyboardInterrupt()


signal.signal(signal.SIGINT, say_good_bye)

while True:
    print('waiting')
    sleep(30)

p.s. 本文使用 Ubuntu / python 3.5.2

執行上述程式後,再按下 CTRL + C 時會得到以下結果,可以看到程式結束之前印出了 Good Bye 字串:

waiting
^C
Good Bye

Traceback (most recent call last):
  File "test_signal.py", line 16, in <module>
    sleep(30)
  File "test_signal.py", line 9, in say_good_bye
    raise KeyboardInterrupt()
KeyboardInterrupt

實際上,按下 CTRL + C 後作業系統會送出 SIGINT signal (Windows 使用者可以使用 signal.CTRL_C_EVENT ) ,因此上述程式利用 signal.signal(signal.SIGINT, say_good_bye) 捕捉 SIGINT signal ,並將之交給 handler say_good_bye 處理。

一個處理 signal 的 handler 必須接受 2 個參數分別為 signal number 及現在的 stack frame ,所以 say_good_bye 也定義可接受 2 個參數。

The handler is called with two arguments: the signal number and the current stack frame

印出 Good Bye 後,程式仍必須結束才行,因此在 say_good_bye 的最後,重新 raise CTRL + C 產生的 KeyboardInterrupt 以結束程式,如果沒有這行的話,程式一直按 CTRL + C 也不會結束,得透過 kill 指令才能結束。

學會上述範例後,基本上 signal 也已經有個概括了解的程度了,剩下的就是一些使用上的注意事項。

在 POSIX 環境中, SIGKILL SIGSTOP 是不可被捕捉的,所以上述定為捕捉 SIGKILLSIGSTOP signal 時,將會出現以下錯誤。

Except for the SIGKILL and SIGSTOP signals, the signal() function allows for a signal to be caught, to be ignored, or to generate an interrupt.

>>> signal.signal(signal.SIGKILL, say_good_bye)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "test_signal.py", line 47, in signal
    handler = _signal.signal(_enum_to_int(signalnum), _enum_to_int(handler))
OSError: [Errno 22] Invalid argument

再來是根據 Python 文件中的一段話:

Python signal handlers are always executed in the main Python thread, even if the signal was received in another thread. This means that signals can’t be used as a means of inter-thread communication. You can use the synchronization primitives from the threading module instead.

signal 的 handlers 永遠都會在 main thread 中被執行,所以不要以為 main thread 以外的 thread 會執行 handler ,也因此 signal 注定不適合用來做 thread 間的溝通,如果要做 thread 間的溝通可以參閱最簡單的 Event Object

以上就是 Python 內建模組 signal 的淺談。

References

https://docs.python.org/3/library/signal.html

https://docs.python.org/3/library/threading.html#event-objects

對抗久坐職業傷害

研究指出每天增加 2 小時坐著的時間,會增加大腸癌、心臟疾病、肺癌的風險,也造成肩頸、腰背疼痛等常見問題。

然而對抗這些問題,卻只需要工作時定期休息跟伸展身體即可!

你想輕鬆改變現狀嗎?試試看我們的 PomodoRoll 番茄鐘吧! PomodoRoll 番茄鐘會根據你所設定的專注時間,定期建議你 1 項辦公族適用的伸展運動,幫助你打敗久坐所帶來的傷害!

贊助我們的創作

看完這篇文章了嗎? 休息一下,喝杯咖啡吧!

如果你覺得 MyApollo 有讓你獲得實用的資訊,希望能看到更多的技術分享,邀請你贊助我們一杯咖啡,讓我們有更多的動力與精力繼續提供高品質的文章,感謝你的支持!