在KeyboardInterrupt时,BoundedSemaphore在线程中挂起
如果你在尝试获取一个信号量的时候按下了键盘中断(比如 Ctrl+C),那么其他也在尝试释放这个信号量的线程就会一直卡在那里,无法继续。
代码:
import threading
import time
def worker(i, sema):
time.sleep(2)
print i, "finished"
sema.release()
sema = threading.BoundedSemaphore(value=5)
threads = []
for x in xrange(100):
sema.acquire()
t = threading.Thread(target=worker, args=(x, sema))
t.start()
threads.append(t)
启动这个程序,然后在它运行的时候按 Ctrl+C。它会卡住,永远不会退出。
0 finished
3 finished
1 finished
2 finished
4 finished
^C5 finished
Traceback (most recent call last):
File "/tmp/proof.py", line 15, in <module>
sema.acquire()
File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/threading.py", line 290, in acquire
self.__cond.wait()
File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/threading.py", line 214, in wait
waiter.acquire()
KeyboardInterrupt
6 finished
7 finished
8 finished
9 finished
我该怎么做才能让最后几个线程正常结束,然后程序正常退出呢?(如果你不去中断它,它是可以正常退出的)
5 个回答
0
在这种情况下,看起来你可能只想用一个线程池来控制线程的启动和停止。你可以使用Chris Arndt的线程池库,用法大概是这样的:
pool = ThreadPool(5)
try:
# enqueue 100 worker threads
pool.wait()
except KeyboardInterrupt, k:
pool.dismiss(5)
# the program will exit after all running threads are complete
1
在你原来的代码中,你还可以把线程设置为守护线程。当你中断脚本时,这些守护线程就会像你预期的那样全部结束。
t = ...
t.setDaemon(True)
t.start()
2
你可以使用信号模块来设置一个标志,这个标志会告诉主线程停止处理:
import threading
import time
import signal
import sys
sigint = False
def sighandler(num, frame):
global sigint
sigint = True
def worker(i, sema):
time.sleep(2)
print i, "finished"
sema.release()
signal.signal(signal.SIGINT, sighandler)
sema = threading.BoundedSemaphore(value=5)
threads = []
for x in xrange(100):
sema.acquire()
if sigint:
sys.exit()
t = threading.Thread(target=worker, args=(x, sema))
t.start()
t.join()
threads.append(t)