BoundedSemaphore在KeyboardInterrupt上的线程中挂起

时间:2009-06-01 21:40:36

标签: python multithreading

如果在尝试获取信号量时引发KeyboardInterrupt,则尝试释放相同信号量对象的线程将无限期挂起。

代码:

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)

启动它,然后^ 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 :(得分: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)

答案 1 :(得分:0)

在这种情况下,看起来您可能只想使用线程池来控制线程的启动和停止。你可以用这样的方式使用Chris Arndt's threadpool library

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

答案 2 :(得分:0)

在原始代码中,您还可以创建线程守护程序线程。当您中断脚本时,守护程序线程将按预期进行死亡。

  t = ...
  t.setDaemon(True)
  t.start()

答案 3 :(得分:0)

这是错误#11714,在较新版本的python中已经patched

如果你使用的是较旧的python,你可以将该补丁中找到的Semaphore版本复制到你的项目中并使用它,而不是依赖于threading中的错误版本

答案 4 :(得分:0)

# importing modules
import threading
import time
# defining our worker and pass a counter and the semaphore to it
def worker(i, sema):
    time.sleep(2)
    print i, "finished"
    # releasing the thread increments the sema value
    sema.release()

# creating the semaphore object
sema = threading.BoundedSemaphore(value=5)
# a list to store the created threads
threads = []
for x in xrange(100):
 try:
   sema.acquire()
   t = threading.Thread(target=worker, args=(x, sema))
   t.start()
   threads.append(t)
 # exit once the user hit CTRL+c
 # or you can make the thead as daemon t.setdaemon(True)
 except KeyboardInterrupt:
   exit()