国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

初步理解Python進(jìn)程的信號通訊

2019-11-25 17:47:22
字體:
供稿:網(wǎng)友

信號的概念

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

幾個常用信號:

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

SIGTERM   終止進(jìn)程     軟件終止信號

SIGKILL   終止進(jìn)程     殺死進(jìn)程

SIGALRM 鬧鐘信號
進(jìn)程結(jié)束信號 SIGTERM和SIGKILL的區(qū)別

SIGTERM比較友好,進(jìn)程能捕捉這個信號,根據(jù)您的需要來關(guān)閉程序。在關(guān)閉程序之前,您可以結(jié)束打開的記錄文件和完成正在做的任務(wù)。在某些情況下,假如進(jìn)程正在進(jìn)行作業(yè)而且不能中斷,那么進(jìn)程可以忽略這個SIGTERM信號。

對于SIGKILL信號,進(jìn)程是不能忽略的。這是一個 “我不管您在做什么,立刻停止”的信號。假如您發(fā)送SIGKILL信號給進(jìn)程,Linux就將進(jìn)程停止在那里。
發(fā)送信號一般有兩種原因:

1(被動式)  內(nèi)核檢測到一個系統(tǒng)事件.例如子進(jìn)程退出會像父進(jìn)程發(fā)送SIGCHLD信號.鍵盤按下control+c會發(fā)送SIGINT信號

2(主動式)  通過系統(tǒng)調(diào)用kill來向指定進(jìn)程發(fā)送信號
linux操作系統(tǒng)提供的信號

[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']

操作系統(tǒng)規(guī)定了進(jìn)程收到信號以后的默認(rèn)行為

但是,我們可以通過綁定信號處理函數(shù)來修改進(jìn)程收到信號以后的行為

有兩個信號是不可更改的SIGTOP和SIGKILL
綁定信號處理函數(shù)

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

運行該程序。然后通過另外一個進(jìn)程來發(fā)送信號。
發(fā)送信號

發(fā)送信號的代碼如下:

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

SIGCHLD信號

然后顯示一個子進(jìn)程結(jié)束后自動向父進(jìn)程發(fā)送SIGCHLD信號的例子。

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

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

如果一個進(jìn)程收到一個SIGUSR1信號,然后執(zhí)行信號綁定函數(shù),第二個SIGUSR2信號又來了,第一個信號沒有被處理完畢的話,第二個信號就會丟棄。

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

這個不妥,測試沒發(fā)現(xiàn)有信號丟失

例子演示:

接收信號的程序,你會發(fā)現(xiàn)如果有另外一端使用多線程向這個進(jìn)程發(fā)送信號,會遺漏一些信號。

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

多線程發(fā)信號端的程序:

 

  '''''''   使用多線程向另外一個進(jìn)程發(fā)送信號   '''    import threading    import os    import signal         def sendusr1():      print '發(fā)送信號'      #這里的進(jìn)程id需要寫前一個程序?qū)嶋H運行的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 '主線程完成'  

內(nèi)容補(bǔ)充:

Alarms 是一個特殊信號類型,它可以讓程序要求系統(tǒng)經(jīng)過一段時間對自己發(fā)送通知。os 標(biāo)準(zhǔn)模塊中指出,它可用于避免無限制阻塞 I/O 操作或其它系統(tǒng)調(diào)用。

像下面例子,原本程序睡眠 10 后才打印出 print 'After :', time.ctime(),但是由于 signal.alarm(2),所以 2 秒后就執(zhí)行了打印。

  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' 語句打印不出來,如果不調(diào)用 signal.alarm(2) ,程序?qū)⒂肋h(yuǎn)阻塞

  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 類信號可以在任何線程中調(diào)用,但是只能在主線程中接收,像下面例子即使子線程 use_alarm 中調(diào)用  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' 

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 宁强县| 宁津县| 平湖市| 通许县| 铁力市| 南投县| 青田县| 宁河县| 安宁市| 太仓市| 榕江县| 略阳县| 乌拉特中旗| 喀什市| 朝阳县| 石首市| 上林县| 鹤壁市| 桓台县| 乌拉特前旗| 大田县| 海林市| 布拖县| 平昌县| 连南| 大洼县| 海口市| 大厂| 栾川县| 巍山| 佛山市| 松江区| 湖北省| 涞源县| 达拉特旗| 灵宝市| 建瓯市| 潼关县| 桃江县| 嵩明县| 安顺市|