python進程間通訊--信號Signal

信號signal 是python進程間通訊多種機制中的其中一種機制。能夠對操做系統進程的控制,當進程中發生某種緣由而中斷時,能夠異步處理這個異常。html

信號經過註冊的方式‘掛’在一個進程中,而且不會阻塞該進程的運行。一個進程一旦接收到其餘進程(多是應用中的其餘進程,也可能使操做系統中的進程)發送的信號就會打斷原來的程序執行流程來處理這個信號。python

 

名詞理解:linux

異步: 程序在執行中利用內核功能幫助完成必要的輔助操做,不影響應用層持續執行編程

注意: 這裏的同步和異步機制是相對多進程而言的。windows

 

在多個進程中通訊的機制中,只有singal是異步執行的,另外python進程間通訊的機制還有pipe(管道),queue(隊列),value(共享空間)等等。後端

 

signal能夠用在什麼地方?異步

siganl的應用: 編程語言

1. 故障定位技術(進程的底層故障,例如進程忽然中斷和一些可能性較小的故障)函數

2. 對進程的流程控制  ui

 

首先說說與信號signal有關的幾個函數

(1)os.kill(pid,sig)

發送一個信號給某個進程

參數解析:

pid 指定發送信號的進程號

sig  要發送的信號代號(須要經過signal模塊獲取)

 

(2)signal.alarm(sec)  非阻塞函數

設置時鐘信號,在必定時間後給自身發送一個SIGALRM信號

 

原理: 時鐘的建立是進程交由操做系統內核(kernal)幫助建立的

時鐘和進程之間是異步執行的,當時鍾到時,內核會發送信號給進程,進程接收信號進行相應的響應操做。

注意:若是設置多個時鐘,後面的時鐘會覆蓋前面的時鐘,一個進程只有一個掛起的時鐘。

 

(3)signal.pause()

阻塞進程,等待一個信號.當接收到信號時就會中止阻塞

例如:等待signal()函數的發送

 

(4)signal.signal(sig,handler)

這是信號中最關鍵的一個方法,用於聲明一個信號。當進程運行過程當中出現故障異常或者須要進程間通訊時,由操做系統內核中的進程或者應用中的進程發出處理信號,通知註冊了信號的進程進行處理。

signal.signal(sig,handler)

參數理解:

sig 要處理的信號名稱

handler 信號處理方法  

可選值: SIG_DFL    表示默認方法處理

               SIG_IGN    表示忽略這個信號(通常爲了不父進程和子進程的互相干擾而使用)

               handler       自定義回調函數

 

自定義回調函數handler:

這個是當用於在進程捕捉到其餘進程發送的信號時調用的函數,當此函數返回時,進程繼續繼續按原來的邏輯順序執行。此函數在定義時python普通函數的定義沒有區別。函數名不必定是handler,但做爲做爲參數傳入signal()方法的參數名必定是與定義handler函數的函數相同。

def  handler(signum,frame):

    do  something…

 1)sig :接收到的信號編號,signal模塊內部定義了一些經常使用的內核信號,併爲它們進行了編號。

例如:

windows操做系統下

SIGNALINT編號爲2

>>>signal.SIGINT

<Signals.SIGINT: 2>

SIGBREAK編號爲21

>>>signal.SIGBREAK

<Signals.SIGBREAK: 21>

注意:windows操做系統沒有SIGUSR1和SIGUSR2這兩個型號類型,linux操做系統纔有。

 

2) frame:信號結構對象(能夠經過結構對象查看信號信息,基本不用)

 

signal函數其實是一個異步的回調函數,只要執行了該函數,則進程任意時候接收到相應信號都會處理。 這裏的異步就是上文提到的異步機制,是計算機內核程序與本進程間同時運行,互相不干擾的一種機制,對於進程的正常執行有着關鍵的做用。這種異步機制在任何後端編程語言中都是存在的,只不過實現的方式和細節不同而已。

 

singnal怎麼用?

通常信號signal是在須要檢測異常的程序的開頭就定義好了,程序順序向下運行時,一旦捕獲到操做系統發出的signal或者其餘進程發出的signal,立刻就會中止當前的程序運行狀態,去處理捕獲到的signal。

案例:
註冊signal import signal import os import time print("The process's PID is:",os.getpid()) def handle_signal(signum,frame): print('Received and handle:',signum) #註冊信號處理程序
signal.signal(signal.SIGUSR1,handle_signal) signal.signal(signal.SIGUSR2,handle_signal) print("The process's PID is:",os.getpid()) while True: print('Waiting...') print(time.ctime()) time.sleep(2)

 

終端分別輸入輸入:
>>> os.kill(7094,signal.SIGUSR1) >>> os.kill(7094,signal.SIGUSR2)

結果:

Waiting... Sat Nov 17 12:19:26 2018 Waiting... Sat Nov 17 12:19:28 2018 Received and handle: 10 Waiting... Sat Nov 17 12:19:30 2018 Waiting... Sat Nov 17 12:22:21 2018 Received and handle: 12 Waiting... Sat Nov 17 12:22:23 2018

 

 

處理interrupt

import signal import os import sys import time print("The process's PID is:",os.getpid()) def handle_signal(signum,frame): print('Received and handle:',signum) def handle_interrupt(signum,frame): print('Receive keyboard interrupt') sys.exit(0) #退出進程

#註冊信號處理程序
signal.signal(signal.SIGINT,handle_interrupt) signal.signal(signal.SIGUSR1,handle_signal) while True: print('Waiting...') print(time.ctime()) time.sleep(2)

終端輸入:

>>> os.kill(7625,signal.SIGINT)

會退出進程

 

若是註冊函數改成

signal.signal(signal.SIGINT,signal.SIG_IGN)

則會忽略終端發出的SIGINT

 

時鐘

給signal設定時鐘 def handle_signal(signum,frame): print('Time is up!',signum) sys.exit() signal.signal(signal.SIGALRM,handle_signal) signal.alarm(3) while True: print(time.ctime()) time.sleep(1)

結果:

Sat Nov 17 13:21:51 2018 Sat Nov 17 13:21:52 2018 Sat Nov 17 13:21:53 2018 Time is up! 14

 

附錄:

windows下的sig信號類型

>>> dir(signal)

['CTRL_BREAK_EVENT', 'CTRL_C_EVENT', 'Handlers', 'NSIG', 'SIGABRT', 'SIGBREAK', 'SIGFPE', 'SIGILL', 'SIGINT', 'SIGSEGV', 'SIGTERM', 'SIG_DFL', 'SIG_IGN', 'Signals', '_IntEnum', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_enum_to_int', '_int_to_enum', '_signal', 'default_int_handler', 'getsignal', 'set_wakeup_fd', 'signal']

 

linux下的sig信號類型

>>> dir(signal)

['ITIMER_PROF', 'ITIMER_REAL', 'ITIMER_VIRTUAL', 'ItimerError', '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__', '__package__', 'alarm', 'default_int_handler', 'getitimer', 'getsignal', 'pause', 'set_wakeup_fd', 'setitimer', 'siginterrupt', 'signal']

 

經常使用信號類型解析

SIGHUP   斷開鏈接

SIGINT    ctrl-C

SIGUIT    ctrl-\

SIGTSTP   ctrl-z

SIGKILL    終止進程且不能被處理

SIGSTOP   暫停進程且不能被處理

SIGALRM   時鐘進程

SIGCHLD   子進程狀態改變發送給父進程信息號(但通常父進程不會處理)

 

參考文章:

https://www.cnblogs.com/xautxuqiang/p/5339602.html

https://www.cnblogs.com/madsnotes/articles/5688681.html

相關文章
相關標籤/搜索