Python之signal模塊的使用


常用的信號值如下:

信號值                    事件                                        處理方式
SIGHUP                    終止進程                                    終端線路掛斷
SIGINT                    終止進程                                    中斷進程
SIGQUIT                    "建立CORE文件終止進程,並且生成core文件"    
SIGILL                    建立CORE文件                                非法指令
SIGTRAP                    建立CORE文件                                跟蹤自陷
SIGBUS                    建立CORE文件                                總線錯誤
SIGSEGV                    建立CORE文件                                段非法錯誤
SIGFPE                    建立CORE文件                                浮點異常
SIGIOT                    建立CORE文件                                執行I/O自陷
SIGKILL                    終止進程                                    殺死進程
SIGPIPE                    終止進程                                    向一個沒有讀進程的管道寫數據
SIGALARM                終止進程                                    計時器到時
SIGTERM                    終止進程                                    軟件終止信號
SIGSTOP                    停止進程                                    非終端來的停止信號
SIGTSTP                    停止進程                                    終端來的停止信號
SIGCONT                    忽略信號                                    繼續執行一個停止的進程
SIGURG                    忽略信號                                    I/O緊急信號
SIGIO                    忽略信號                                    描述符上可以進行I/O
SIGCHLD                    忽略信號                                    當子進程停止或退出時通知父進程
SIGTTOU                    停止進程                                    后台進程寫終端
SIGTTIN                    停止進程                                    后台進程讀終端
SIGXGPU                    終止進程                                    CPU時限超時
SIGXFSZ                    終止進程                                    文件長度過長
SIGWINCH                忽略信號                                    窗口大小發生變化
SIGPROF                    終止進程                                    統計分布圖用計時器到時
SIGUSR1                    終止進程                                    用戶定義信號1
SIGUSR2                    終止進程                                    用戶定義信號2
SIGVTALRM                終止進程                                    虛擬計時器到時

 1、接收信號綁定處理對應的事件

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import signal
import os
import time

def receive_signal(signum, stack):
    """用於接收信號,對signum的值區分信號,實現不同的信號做對應的處理"""
    print('接收的signum', signum)

#注冊處理信號的事件,此處對用戶定義信號1、用戶定義信號2,綁定事件
signal.signal(signal.SIGUSR1, receive_signal)
signal.signal(signal.SIGUSR2, receive_signal)

print('我的PID: %s' % os.getpid())

#開啟循環監聽信號
while True:
    print('Waiting...')
    time.sleep(3)
signal_signal.py

運行效果

#終端1
[root@ mnt]# python3 signal_signal.py 
我的PID: 14718
Waiting... #==>每3秒打印一次
Waiting...
Waiting...
接收的signum 10 #==>接收到kill -USR1 14718的命令,作出的動作
Waiting...
接收的signum 12 #==>接收到kill -USR2 14718的命令,作出的動作
Waiting...
Waiting...
Traceback (most recent call last): #==>接收到kill -INT 14718命令的動作
  File "signal_signal.py", line 22, in <module>
    time.sleep(3)
KeyboardInterrupt

#終端2
[root@ ~]# kill -USR1 14718
[root@ ~]# kill -USR2 14718
[root@ ~]# kill -INT 14718 

 2、獲取已注冊信號處理器事件

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import signal

def alarm_received(n, stack):
    return

signal.signal(signal.SIGALRM, alarm_received)

# 字典格式:{<Signals.SIGABRT: 6>: 'SIGIOT', <Signals.SIGALRM: 14>: 'SIGALRM'...}
signals_to_names = {
    getattr(signal, n): n
    for n in dir(signal) if n.startswith('SIG') and '_' not in n
}

for s, name in sorted(signals_to_names.items()):
    handler = signal.getsignal(s)  # 獲取信號的有沒有綁定信號事件
    if handler is signal.SIG_DFL:  # 判斷有沒有綁定信號事件,沒有的話,設置為SIG_DFL或SIG_IGN
        handler = 'SIG_DFL'
    elif handler is signal.SIG_IGN:
        handler = 'SIG_IGN'
    print('{:<10} ({:2d}):'.format(name, s), handler)
signal_getsignal.py

運行效果

[root@ mnt]# python3 signal_getsignal.py 
SIGHUP     ( 1): SIG_DFL
SIGINT     ( 2): <built-in function default_int_handler>
SIGQUIT    ( 3): SIG_DFL
SIGILL     ( 4): SIG_DFL
SIGTRAP    ( 5): SIG_DFL
SIGIOT     ( 6): SIG_DFL
SIGBUS     ( 7): SIG_DFL
SIGFPE     ( 8): SIG_DFL
SIGKILL    ( 9): SIG_DFL
SIGUSR1    (10): SIG_DFL
SIGSEGV    (11): SIG_DFL
SIGUSR2    (12): SIG_DFL
SIGPIPE    (13): SIG_IGN
SIGALRM    (14): <function alarm_received at 0x7f2bc1002e18>
SIGTERM    (15): SIG_DFL
SIGCLD     (17): SIG_DFL
SIGCONT    (18): SIG_DFL
SIGSTOP    (19): SIG_DFL
SIGTSTP    (20): SIG_DFL
SIGTTIN    (21): SIG_DFL
SIGTTOU    (22): SIG_DFL
SIGURG     (23): SIG_DFL
SIGXCPU    (24): SIG_DFL
SIGXFSZ    (25): SIG_IGN
SIGVTALRM  (26): SIG_DFL
SIGPROF    (27): SIG_DFL
SIGWINCH   (28): SIG_DFL
SIGPOLL    (29): SIG_DFL
SIGPWR     (30): SIG_DFL
SIGSYS     (31): SIG_DFL
SIGRTMIN   (34): SIG_DFL
SIGRTMAX   (64): SIG_DFL

 3、發送信號

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import signal
import sys
os.kill(int(sys.argv[1]),signal.SIGUSR1)
signal_send.py

 4、告警信號

import signal
import time

def receive_alarm(signum, stack):
    print('告警時間 :', time.ctime())

signal.signal(signal.SIGALRM, receive_alarm)
signal.alarm(2) #2秒后調用SIGALRM信號的事件

print('之前運行時間:', time.ctime())
time.sleep(4)
print('之后運行時間: :', time.ctime())
signal_alarm.py

運行效果

[root@ mnt]# python3 signal_alarm.py 
之前運行時間: Thu Dec  5 16:02:11 2019
告警時間 : Thu Dec  5 16:02:13 2019
之后運行時間: : Thu Dec  5 16:02:15 2019

 5、怱略信號

import signal
import os

def do_exit(sig, stack):
    raise SystemExit('Exiting')  # 退出程序並打印顯示

# 注冊使用SIGINT發送信號,做忽略處理
signal.signal(signal.SIGINT, signal.SIG_IGN)

# 注冊使用SIGUSR1發送信號,交給do_exit函數處理
signal.signal(signal.SIGUSR1, do_exit)

print('我的PID: %s' % os.getpid())

signal.pause()  # 暫停
signal_ignore.py

運行效果

#終端1
#Ctrl+C,失效,因為Ctrl+C發送的信號是SIGINT,已經被怱略
[root@ mnt]# python3 signal_ignore.py 
我的PID: 15042
^C^C^C^C^C^C^C

#終端2
#方法1、殺死不了進程
[root@ mnt]# kill -INT 15042 

#方法2、可以殺死進程
[root@ mnt]# kill -USR1 15042

 6、開啟兩個線程相互接收信號

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import signal
import threading
import os
import time

def signal_handler(num, stack):
    print('接收信號 SIG值{} 線程名字{}'.format(num, threading.currentThread().name))

# 給SIGUSR1注冊處理事件
signal.signal(signal.SIGUSR1, signal_handler)

#等待接收信號
def wait_for_signal():
    print('等待信號進來', threading.currentThread().name)
    signal.pause()
    print('完成等持')


# 啟動不會接收信號的線程
receiver = threading.Thread(
    target=wait_for_signal,
    name='receiver',
)
receiver.start()
time.sleep(0.1)

#給主進程發送SIGUSR1信號
def send_signal():
    print('發送SIGUSR1信號', threading.currentThread().name)
    os.kill(os.getpid(), signal.SIGUSR1)

sender = threading.Thread(target=send_signal, name='sender')
sender.start()
sender.join()

# 等待線程看到信號
print('Waiting for', receiver.name)
signal.alarm(2) #2秒后,發出告警信號,終止程序,如果沒有加入此代碼,會導致無限阻塞
receiver.join()
signal_threads.py

運行效果

[root@ mnt]# python3 signal_threads.py      
等待信號進來 receiver
發送SIGUSR1信號 sender
接收信號 SIG值10 線程名字MainThread
Waiting for receiver
Alarm clock

 7、多進程與告警信號配合使用

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import signal
import time
import threading

def signal_handler(num, stack):
    print(time.ctime(), '處理告警的線程名字', threading.currentThread().name)


# 注冊SIGALRM信號的事件
signal.signal(signal.SIGALRM, signal_handler)


def use_alarm():
    t_name = threading.currentThread().name
    print(time.ctime(), '設置1秒后觸發告警', t_name)
    signal.alarm(1)
    print(time.ctime(), '睡眠3秒', t_name)
    time.sleep(3)
    print(time.ctime(), '完成睡眠', 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(), '等待執行完成', alarm_thread.name)
alarm_thread.join()

print(time.ctime(), '正常退出')
signal_threads_alarm.py

運行效果

[root@ mnt]# python3 signal_threads_alarm.py 
Thu Dec  5 16:37:05 2019 設置1秒后觸發告警 alarm_thread
Thu Dec  5 16:37:05 2019 睡眠3秒 alarm_thread
Thu Dec  5 16:37:05 2019 等待執行完成 alarm_thread
Thu Dec  5 16:37:06 2019 處理告警的線程名字 MainThread
Thu Dec  5 16:37:08 2019 完成睡眠 alarm_thread
Thu Dec  5 16:37:08 2019 正常退出


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM