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
是不可被捕捉的,所以上述定為捕捉 SIGKILL
或 SIGSTOP
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