Python訊號處理

2021-07-31 09:35:19 字數 3422 閱讀 4610

通常我們認為,在try語句中,finally一定會執行。

# coding: utf-8

import time

import os

import logging

try:

print

'start try, sleep 30s...'

print

'pid: %s' % os.getpid()

time.sleep(30)

print

'end try'

except exception, e:

print

'catch exception'

logging.exception(e)

except keyboardinterrupt, e:

logging.exception(e)

finally:

print

'oh, finally'

上面這段程式,用ctrl-c來終止程式時,可以捕獲到乙個keyboardinterrupt,finally也會執行。

start try, sleep 30s...

pid: 9900

oh, finally

error:root:

traceback (most recent call

last):

file "/users/bowen/python/learn-python/exceptions/finally_test.py", line 9, in

time.sleep(30)

keyboardinterrupt

但是如果在命令列,採用 kill -9 pid方式終止程式,程式會強制退出,finally後面的**段也不會執行。

那麼兩種情況不同是什麼原因呢?

本質區別在於python程序對於訊號的處理。訊號(signal)是程序之間通訊的方式,是一種軟體中斷。乙個程序一旦接收到訊號就會打斷原來的程式執行流程來處理訊號。

幾個常用訊號:

sigint    終止程序  中斷程序  (control+c)

sigterm 終止程序 軟體終止訊號

sigkill 終止程序 殺死程序

sigalrm 鬧鐘訊號

sigchld 子程序終止向父程序傳送的訊號

control+c會傳送sigint訊號,並產生keyboardinterrupt異常。kill -9會傳送sigkill訊號。sigterm和sigkill都是程序結束訊號。

sigkill訊號是無法在程式內部捕獲的,一旦傳送sigkill訊號給程序,linux就將程序停止在那裡。python自己並不檢查sigkill,而是直接把底層標準c的執行時錯誤返回。在python**中,sigkill無法捕捉,而且無法忽略。一般關於sigkill的日誌在/var/log/messages裡,如果非deamon程式在終端也是有日誌體現的。

sigterm比較友好,程序能捕捉這個訊號,根據需要來關閉程式。在關閉程式之前,可以結束開啟的記錄檔案和完成正在做的任務。在某些情況下,假如程序正在進行作業而且不能中斷,那麼程序可以忽略這個sigterm訊號。

傳送訊號一般有兩種原因:

1. (被動式) 核心檢測到乙個系統事件。例如子程序退出會像父程序傳送sigchld訊號.鍵盤按下control+c會傳送sigint訊號。

2. (主動式) 通過系統呼叫kill來向指定程序傳送訊號。

>>> 

import signal

>>> dir(signal)

['nsig', 'sigabrt', 'sigalrm', 'sigbus', 'sigchld', 'sigcld', 'sigcont', 'sigfpe', 'sighup', 'sigill', 'sigint', 'sigio', 'sigiot', 'sigkill', 'sigpipe', 'sigpoll', 'sigprof', 'sigpwr', 'sigquit', 'sigrtmax', 'sigrtmin', 'sigsegv', 'sigstop', 'sigsys', 'sigterm', 'sigtrap', 'sigtstp', 'sigttin', 'sigttou', 'sigurg', 'sigusr1', 'sigusr2', 'sigvtalrm', 'sigwinch', 'sigxcpu', 'sigxfsz', 'sig_dfl', 'sig_ign', '__doc__', '__name__', 'alarm', 'default_int_handler', 'getsignal', 'pause', 'signal']

作業系統規定了程序收到訊號以後的預設行為。但是,我們可以通過繫結訊號處理函式來修改程序收到訊號以後的行為,有兩個訊號是不可更改的:sigtop和sigkill。

子程序向父程序傳送乙個signal.sigterm訊號的例子。

# coding: utf-8

import os

import signal

import time

defcatch_signal

(a, b):

print

'catch signal, %s' % os.getpid()

signal.signal(signal.sigterm, catch_signal)

try:

pid = os.fork()

if pid == 0:

print

'child process, %s' % os.getpid()

time.sleep(1)

# kill a process with a signal.

os.kill(os.getppid(), signal.sigterm)

else:

print

'parent process, %s' % os.getpid()

print

'wait child ...'

os.wait()

except exception, e:

print e

pass

print

'end %s' % os.getpid()

執行結果:

parent process, 14901

wait child ...

child process, 14902

end 14902

catch signal, 14901

[errno 4] interrupted system call

end 14901

如果乙個程序收到乙個sigusr1訊號,然後執行訊號繫結函式,第二個sigusr2訊號又來了,第乙個訊號沒有被處理完畢的話,第二個訊號就會丟棄。所以,盡量不要在多執行緒中使用訊號。

訊號機制 Python訊號處理 signal模組

本文是訊號機制三篇記錄中的第二篇,介紹python語言中負責訊號處理的signal模組,並會給出一些小demo 第一篇簡單介紹了linux訊號機制,第三篇則給出關於訊號的乙個應用。三篇組成乙個系列,想起拋磚引玉的作用,希望對大家能有所幫助。該模組提供python中訊號處理的機制,下面是幾個常用的方法...

python 訊號處理模組signal

signal包負責在python程式內部處理訊號,典型的操作包括預設訊號處理函式,暫停並等待訊號,以及定時發出sigalrm等。要注意,signal包主要是針對unix平台 比如linux,mac os 而windows核心中由於對訊號機制的支援不充分 signal包定義了各個訊號名及其對應的整數,...

Python 訊號處理 signal 模組

官方文件上有這樣的示例 import signal,os 定義乙個訊號處理函式,該函式列印收到的訊號,然後raise ioerror def handler signum,frame print signal handler called with signal signum raise ioerr...