初步理解Python進程的訊號通訊_python

來源:互聯網
上載者:User

訊號的概念

訊號(signal)--     進程之間通訊的方式,是一種軟體中斷。一個進程一旦接收到訊號就會打斷原來的程式執行流程來處理訊號。

幾個常用訊號:

SIGINT     終止進程  中斷進程  (control+c)

SIGTERM   終止進程     軟體終止訊號

SIGKILL   終止進程     殺死進程

SIGALRM 鬧鐘訊號
進程結束訊號 SIGTERM和SIGKILL的區別

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

對於SIGKILL訊號,進程是不能忽略的。這是一個 “我不管您在做什麼,立刻停止”的訊號。假如您發送SIGKILL訊號給進程,Linux就將進程停止在那裡。
發送訊號一般有兩種原因:

1(被動式)  核心檢測到一個系統事件.例如子進程退出會像父進程發送SIGCHLD訊號.鍵盤按下control+c會發送SIGINT訊號

2(主動式)  通過系統調用kill來向指定進程發送訊號
linux作業系統提供的訊號

[100003@oss235 myppt]$ 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

Python提供的訊號

Python 2.4.3 (#1, Jun 11 2009, 14:09:58)[GCC 4.1.2 20080704 (Red Hat 4.1.2-44)] on linux2Type "help", "copyright", "credits" or "license" for more information.>>> 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
綁定訊號處理函數

  import os    import signal    from time import sleep         def onsignal_term(a,b):      print '收到SIGTERM訊號'         #這裡是綁定訊號處理函數,將SIGTERM綁定在函數onsignal_term上面    signal.signal(signal.SIGTERM,onsignal_term)         def onsignal_usr1(a,b):      print '收到SIGUSR1訊號'    #這裡是綁定訊號處理函數,將SIGUSR1綁定在函數onsignal_term上面    signal.signal(signal.SIGUSR1,onsignal_usr1)         while 1:      print '我的進程id是',os.getpid()      sleep(10)  

運行該程式。然後通過另外一個進程來發送訊號。
發送訊號

發送訊號的代碼如下:

  import os    import signal         #發送訊號,16175是前面那個綁定訊號處理函數的pid,需要自行修改    os.kill(16175,signal.SIGTERM)    #發送訊號,16175是前面那個綁定訊號處理函數的pid,需要自行修改    os.kill(16175,signal.SIGUSR1)  

SIGCHLD訊號

然後顯示一個子進程結束後自動向父進程發送SIGCHLD訊號的例子。

  '''''''   子進程結束會向父進程發送SIGCHLD訊號   '''    import os    import signal    from time import sleep         def onsigchld(a,b):      print '收到子進程結束訊號'    signal.signal(signal.SIGCHLD,onsigchld)         pid = os.fork()    if pid == 0:      print '我是子進程,pid是',os.getpid()      sleep(2)    else:      print '我是父進程,pid是',os.getpid()      os.wait() #等待子進程結束  

使用訊號需要特別注意的地方:

如果一個進程收到一個SIGUSR1訊號,然後執行訊號綁定函數,第二個SIGUSR2訊號又來了,第一個訊號沒有被處理完畢的話,第二個訊號就會丟棄。

所以,盡量不要在多線程中使用訊號。

這個不妥,測試沒發現有訊號丟失

例子示範:

接收訊號的程式,你會發現如果有另外一端使用多線程向這個進程發送訊號,會遺漏一些訊號。

  import os    import signal    from time import sleep    import Queue         QCOUNT = Queue.Queue() #初始化隊列         def onsigchld(a,b):      '''''''收到訊號後向隊列中插入一個數字1'''      print '收到SIGUSR1訊號'      sleep(2)      QCOUNT.put(1) #向隊列中寫入       def exithanddle(s,e):     raise SystemExit('收到終止命令,退出程式')       signal.signal(signal.SIGUSR1,onsigchld) #綁定訊號處理函數    signal.signal(signal.SIGINT,exithanddle) #當按下Ctrl + C 終止進程        while 1:      print '我的pid是',os.getpid()      print '現在隊列中元素的個數是',QCOUNT.qsize()      sleep(2) 

多線程發訊號端的程式:

 

  '''''''   使用多線程向另外一個進程發送訊號   '''    import threading    import os    import signal         def sendusr1():      print '發送訊號'      #這裡的進程id需要寫前一個程式實際啟動並執行pid      os.kill(17788, signal.SIGUSR1)          WORKER = []         #開啟6個線程    for i in range(1, 7):      threadinstance = threading.Thread(target = sendusr1)      WORKER.append(threadinstance)         for i in WORKER:      i.start()         for i in WORKER:      i.join()         print '主線程完成'  

內容補充:

Alarms 是一個特殊訊號類型,它可以讓程式要求系統經過一段時間對自己發送通知。os 標準模組中指出,它可用於避免無限制阻塞 I/O 操作或其它系統調用。

像下面例子,原本程式睡眠 10 後才列印出 print 'After :', time.ctime(),但是由於 signal.alarm(2),所以 2 秒後就執行了列印。

  import signal   import time      def receive_alarm(signum, stack):     print 'Alarm :', time.ctime()      # Call receive_alarm in 2 seconds   signal.signal(signal.SIGALRM, receive_alarm)   signal.alarm(2)      print 'Before:', time.ctime()   time.sleep(10)   print 'After :', time.ctime()  

注意Signal只有主線程才能接收訊號,像下面例子,print 'Done waiting' 語句列印不出來,如果不調用 signal.alarm(2) ,程式將永遠阻塞

  import signal   import threading   import os   import time      def signal_handler(num, stack):     print 'Received signal %d in %s' % \       (num, threading.currentThread().name)      signal.signal(signal.SIGUSR1, signal_handler)      def wait_for_signal():     print 'Waiting for signal in', threading.currentThread().name     signal.pause()     print 'Done waiting'      # Start a thread that will not receive the signal   receiver = threading.Thread(target=wait_for_signal, name='receiver')   receiver.start()   time.sleep(0.1)      def send_signal():     print 'Sending signal in', threading.currentThread().name     os.kill(os.getpid(), signal.SIGUSR1)      sender = threading.Thread(target=send_signal, name='sender')   sender.start()   sender.join()      # Wait for the thread to see the signal (not going to happen!)   print 'Waiting for', receiver.name   signal.alarm(2)   receiver.join() 

還有一點需要注意的是,雖然 alarms 類訊號可以在任何線程中調用,但是只能在主線程中接收,像下面例子即使子線程 use_alarm 中調用  signal.alarm(1) ,但是不起作用 :

  import signal   import time   import threading      def signal_handler(num, stack):     print time.ctime(), 'Alarm in', threading.currentThread().name      signal.signal(signal.SIGALRM, signal_handler)      def use_alarm():     t_name = threading.currentThread().name     print time.ctime(), 'Setting alarm in', t_name     signal.alarm(1)     print time.ctime(), 'Sleeping in', t_name     time.sleep(3)     print time.ctime(), 'Done with sleep in', t_name      # Start a thread that will not receive the signal   alarm_thread = threading.Thread(target=use_alarm,                   name='alarm_thread')   alarm_thread.start()   time.sleep(0.1)      # Wait for the thread to see the signal (not going to happen!)   print time.ctime(), 'Waiting for', alarm_thread.name   alarm_thread.join()      print time.ctime(), 'Exiting normally' 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.