問題の要件
マルチスレッド プログラミングでよくある頭痛の問題は、メイン スレッドが終了した後、子スレッドが正常に終了できず、データの損失やファイルの損傷が発生したり、ゾンビ プロセスになってシステム リソースを占有したりすることです。
前回の記事では、スレッドを正常に閉じるいくつかの方法を紹介しましたが、一部のネチズンからは、隠れた危険を残さずにスレッドを暴力的に強制終了することは可能でしょうか?という疑問も提起されました。、答えは「はい!」です。
Python でスレッドを閉じるその他の方法については、私のブログ投稿「Python マルチスレッド プログラミング: スレッドを正常に閉じる方法」を参照してください。
スレッドを暴力的かつ適切にシャットダウンするソリューション
1. ソリューションの説明
1) いわゆる暴力とは、 を押したり、 Ctrl+C
Linux 上でkill -9
強制終了信号を送ったりすることを指します。
2) Pythonsignal
モジュールを通じて、Ctrl+C 信号をリアルタイムでキャプチャし、コールバック関数をトリガーできます。スイッチ変数をオフに設定し、クリーンなコードを実行して、スレッドを閉じます。
3) コードをより堅牢にするために、メインスレッドの終了を担当するカスタム例外クラスが使用されます。
2. 完全なコード
以下は完全なコードです。win10 でテストされました。Ctrl+C キーを押すか、タスク パネルからプロセスを閉じることをサポートして、スレッドを安全に閉じ、隠れた危険を排除します。
Linux システムでは、シグナルを にsignal.SIGTERM
変更するだけでsignal.SIGKILL
、kill -9
コマンドを使用してスレッドを直接強制終了できます。
from math import e
import time
import threading
import signal
class Task(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
# shutdown_flag 用于关闭线程
self.shutdown_flag = threading.Event()
# ... Other thread setup code here ...
def run(self):
print(f'Thread #{
self.ident} started')
while not self.shutdown_flag.is_set():
# 线程代码可以放在这里
print(f"Thread #{
self.ident} is running...")
time.sleep(1)
# ... Clean code put here ...
print(f'Thread #{
self.ident} stopped')
class ServiceExit(Exception):
"""
自定义1个异常类,用于退出线程
"""
def __init__(self,message="force to quit"):
self.message = message
super(ServiceExit,self).__init__(self.message)
# __str__ is to print() the message
def __str__(self):
return(repr(self.message))
def handler_quit(signum, frame):
"""信号处理函数"""
print('Caught signal %d' % signum)
raise ServiceExit("当前线程被强制退出...")
def main():
# 注册信号回调函数
signal.signal(signal.SIGTERM, handler_quit)
signal.signal(signal.SIGINT, handler_quit)
print('Starting main program')
# Start the sub threads
try:
t1 = Task()
t2 = Task()
t1.start()
t2.start()
# 保持主线程运行,否则无法收到信号
while True:
time.sleep(0.5)
except ServiceExit as e:
t1.shutdown_flag.set()
t2.shutdown_flag.set()
# Wait for the threads to close...
t1.join()
t2.join()
print(e.message)
print('Exiting main program')
if __name__ == '__main__':
main()
次のように出力を実行します
Starting main program
Thread #119072 started
Thread #119072 is running...
Thread #119076 started
Thread #119076 is running...
Thread #119076 is running...
Thread #119072 is running...
Thread #119072 is running...
Thread #119076 is running...
Thread #119076 is running...
Thread #119072 is running...
Caught signal 2
Thread #119072 stopped
Thread #119076 stopped
当前线程被强制退出...
Exiting main program