在liunx系統中要想每隔一分鐘執行一個命令,最普遍的方法就是crontab了,如果不想使用crontab,經同事指點在程序中可以用定時器實現這種功能,於是就開始摸索了,發現需要一些訊號的知識...
查看你的linux支援哪些訊號:kill -l 即可
root@server:~# kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX root@server:~#
訊號:進程之間通訊的方式,是一種軟體中斷。一個行程一旦接收到訊號就會打斷原來的程式執行流程來處理訊號。作業系統規定了進程收到訊號以後的預設行為,但是,我們可以透過綁定訊號處理函數來修改進程收到訊號以後的行為,有兩個訊號是不可變更的SIGTOP和SIGKILL。
發送訊號一般有兩種原因:
1(被動式) 核心偵測到一個系統事件.例如子行程退出會像父行程發送SIGCHLD訊號.鍵盤按下control+c會傳送SIGINT訊號
2(主動式) 透過系統呼叫kill來向指定進程發送訊號
在C語言中有個setitimer函數,函數setitimer可以提供三種定時器,它們相互獨立,任意一個定時完成都會發送定時訊號到進程,並且自動重新計時。參數which確定了定時器的類型:
ITIMER_REAL 定時真實時間,與alarm類型相同。 SIGALRM
ITIMER_VIRT 定時程序在使用者狀態下的實際執行時間。 SIGVTALRM
ITIMER_PROF 定時程序在使用者態與核心態的實際執行時間。 SIGPROF
這三種定時器定時完成時給程序發送的信號各不相同,其中ITIMER_REAL類定時器發送SIGALRM信號,ITIMER_VIRT類定時器發送SIGVTALRM信號,ITIMER_REAL類定時器發送SIGPROF信號。
函數alarm本質上設定的是低精確、非重載的ITIMER_REAL類定時器,它只能精確到秒,並且每次設定只能產生一次定時。函數setitimer設定的定時器則不同,它們不但可以計時到微妙(理論上),還能自動循環定時。在一個Unix行程中,不能同時使用alarm和ITIMER_REAL類別計時器。
SIGINT 終止進程 中斷進程 (control+c)
SIGTERM 終止進程 軟體終止訊號
SIGKILL 終止進程 軟體終止訊號
SIGKILL 終止進程 軟體終止訊號
SIGKILL 終止進程 差不多了,該向python的signal進軍了。
定義訊號名稱
signal套件定義了各個訊號名稱及其對應的整數,例如
import signal print signal.SIGALRM print signal.SIGCONT
Python所用的訊號名稱和Linux一致。你可以透過
$man 7 signal
查詢
預設訊號處理函數
signal套件的核心是使用signal.signal()函數來預設(register)訊號處理函數,如下:
singnal.signal(signalnum, handler)
為某一訊號,handler為該訊號的處理函數。我們在訊號基礎裡提到,進程可以無視訊號,可以採取預設操作,還可以自訂操作。當handler為signal.SIG_IGN時,訊號被無視(ignore)。當handler為singal.SIG_DFL,進程採取預設操作(default)。當handler為一個函數名稱時,進程採取函數中定義的操作。
import signal # Define signal handler function def myHandler(signum, frame): print('I received: ', signum) # register signal.SIGTSTP's handler signal.signal(signal.SIGTSTP, myHandler) signal.pause() print('End of Signal Demo')
$python test.py
import signal # Define signal handler function def myHandler(signum, frame): print("Now, it's the time") exit() # register signal.SIGALRM's handler signal.signal(signal.SIGALRM, myHandler) signal.alarm(5) while True: print('not yet')
发送信号
signal包的核心是设置信号处理函数。除了signal.alarm()向自身发送信号之外,并没有其他发送信号的功能。但在os包中,有类似于linux的kill命令的函数,分别为
os.kill(pid, sid) os.killpg(pgid, sid)
分别向进程和进程组(见Linux进程关系)发送信号。sid为信号所对应的整数或者singal.SIG*。
实际上signal, pause,kill和alarm都是Linux应用编程中常见的C库函数,在这里,我们只不过是用Python语言来实现了一下。实际上,Python 的解释器是使用C语言来编写的,所以有此相似性也并不意外。此外,在Python 3.4中,signal包被增强,信号阻塞等功能被加入到该包中。我们暂时不深入到该包中。