我有一些线程正在运行,其中一个线程包含一个将生成子进程的对象。我希望这样的一个子进程能够杀死整个应用程序。上述对象在收到此信号时需要保存一些状态。不幸的是,我无法在导致终止的线程中处理要处理的信号。
下面是一些尝试复制这种情况的示例代码。
parent.py:启动一个线程。该线程运行一些子进程,其中一个子进程将尝试终止父进程。
#!/usr/local/bin/python3
import subprocess, time, threading, random
def killer_func():
possible_cmds = [['echo', 'hello'],
['echo', 'world'],
['/work/turbulencetoo/tmp/killer.py']
]
random.shuffle(possible_cmds)
for cmd in possible_cmds:
try:
time.sleep(2)
subprocess.check_call(cmd)
time.sleep(2)
except KeyboardInterrupt:
print("Kill -2 caught properly!!")
print("Here I could properly save my state")
break
except Exception as e:
print("Unhandled Exception: {}".format(e))
else:
print("No Exception")
killer_thread = threading.Thread(target=killer_func)
killer_thread.start()
try:
while True:
killer_thread.join(4)
if not killer_thread.is_alive():
print("The killer thread has died")
break
else:
print("Killer thread still alive, try to join again.")
except KeyboardInterrupt:
print("Caught the kill -2 in the main thread :(")
print("Main program shutting down")
killer.py,一个尝试使用 SIGINT 终止其父进程的简单程序:
#!/usr/local/bin/python3
import time, os, subprocess, sys
ppid = os.getppid()
# -2 specifies SIGINT, python handles this as a KeyboardInterrupt exception
cmd = ["kill", "-2", "{}".format(ppid)]
subprocess.check_call(cmd)
time.sleep(3)
sys.exit(0)
以下是运行父程序的一些示例输出:
$ ./parent.py
hello
Killer thread still alive, try to join again.
No Exception
Killer thread still alive, try to join again.
Caught the kill -2 in the main thread :(
Main program shutting down
No Exception
world
No Exception
我尝试在 killer_func
中使用 signal.signal()
,但它在子线程中不起作用。
有没有办法在主线程不知道的情况下强制函数处理信号或异常?
最佳答案
程序的主线程始终是接收信号的线程。 signal
module documentation声明如下:
Some care must be taken if both signals and threads are used in the same program. The fundamental thing to remember in using signals and threads simultaneously is: always perform
signal()
operations in the main thread of execution. Any thread can perform analarm()
,getsignal()
,pause()
,setitimer()
orgetitimer()
; only the main thread can set a new signal handler, and the main thread will be the only one to receive signals (this is enforced by the Pythonsignal
module, even if the underlying thread implementation supports sending signals to individual threads). This means that signals can’t be used as a means of inter-thread communication. Use locks instead.
您需要重构您的程序,以便接收信号的主线程不会阻止您保存状态。最简单的方法是使用诸如 threading.Event()
之类的东西来告诉后台线程程序已被中止,并让它在看到事件已设置时进行清理:
import subprocess
import threading
import random
def killer_func(event):
possible_cmds = [['echo', 'hello'],
['echo', 'world'],
['/home/cycdev/killer.py']
]
random.shuffle(possible_cmds)
for cmd in possible_cmds:
subprocess.check_call(cmd)
event.wait(4)
if event.is_set():
print("Main thread got a signal. Time to clean up")
# save state here.
return
event = threading.Event()
killer_thread = threading.Thread(target=killer_func, args=(event,))
killer_thread.start()
try:
killer_thread.join()
except KeyboardInterrupt:
print("Caught the kill -2 in the main thread :)")
event.set()
killer_thread.join()
print("Main program shutting down")
关于python - 在线程中捕获键盘中断或处理信号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30267647/