use*_*759 3 python queue multithreading futex
所以我有一个队列:
q = Queue.Queue()
Run Code Online (Sandbox Code Playgroud)
我在里面放一些东西。
items = ["First", "Second"]
for val in items:
q.put(val)
Run Code Online (Sandbox Code Playgroud)
我正在生成15个线程。
for i in range(15):
tname = 't-%s' % i
t = my_thread(some_func, q, tname)
t.start()
q.join()
Run Code Online (Sandbox Code Playgroud)
my_thread类的外观如下:
class my_thread(threading.Thread):
def __init__(self, some_func, q_, name=''):
threading.Thread.__init__(self)
self.func = some_func
self.process_q = q_
self.name = name
self.prefix = name
def run(self):
stime = time.time()
logging.info('%s thread staring at : %s' % (threading.currentThread().getname(), time.ctime(stime)))
while True:
if self.process_q.empty():
break
queue_item = self.process_q.get()
self.name = self.prefix + '-' + queue_item
try:
#run the function
except Exception as e:
logging.error('Caught some error')
finally:
self.process_q.task_done()
endTime = time.time()
logging.info('%s thread finished at: %s' % (threading.currentThread().getName(), time.ctime(endTime)))
Run Code Online (Sandbox Code Playgroud)
如果我看一下日志,我看到的是两个或多个线程同时访问Queue,而当Queue为空时,while循环不会中断。
假设t-0线程"first"已从队列中取出项目。但是,t-2线程可能采取"second"前项t-1线程可以把它从而使队列空...但是当t-1做了self.process_q.empty()检查,队列不为空。因此t-1线程永远不会退出/结束,而会挂起。
如果我对进程ID进行跟踪,则会得到以下结果:
Process 13307 attached
futex(0x2a5fcc0, FUTEX_WAIT_PRIVATE, 0, NULL
Run Code Online (Sandbox Code Playgroud)
我该如何解决???
您的线程随机挂在阻塞的self.process_q.get()函数中。-> 种族条件
此刻,线程已启动,队列不为空。代码部分...
...
if self.process_q.empty():
break
queue_item = self.process_q.get()
...
Run Code Online (Sandbox Code Playgroud)
未在所有线程上同步。因此可以通过if条件超过2个线程(队列大小= 2)。两个线程正在从self.process_q.get()函数获取结果,而其他线程正在阻塞并等待队列中的结果。
直到所有非守护进程线程都完成后,python程序才能退出。因此它永远挂起。
考虑将线程设置为守护程序模式:
for i in range(15):
tname = 't-%s' % i
t = my_thread(some_func, q, tname)
t.setDaemon(True)
t.start()
Run Code Online (Sandbox Code Playgroud)
来自https://docs.python.org/2/library/threading.html#threading.Thread.daemon:
守护程序
一个布尔值,指示此线程是否是守护程序线程(真)(假)。必须在调用start()之前设置此项,否则会引发RuntimeError。它的初始值是从创建线程继承的;主线程不是守护程序线程,因此在主线程中创建的所有线程默认为daemon = False。
当没有活动的非守护线程时,整个Python程序将退出。
通过将daemon-mode设置为true,程序将在队列为空之后退出(q.join())。