Python threading.Event() - 确保在event.set()上唤醒所有等待的线程

cul*_*ntr 10 python events multithreading

我有许多线程等待事件,执行一些操作,然后再次等待事件.另一个线程将在适当的时候触发事件.

我无法找到一种方法来确保每个等待的线程在设置事件时恰好触发一次.我目前有触发线程设置它,睡了一会儿,然后清除它.不幸的是,这导致等待线程多次抓住设置事件,或者根本没有.

我不能简单地让触发线程产生响应线程来运行它们一次,因为它们是对来自其他地方的请求的响应.

简而言之:在Python中,我如何让线程设置一个事件并确保每个等待线程在被清除之前只对事件执行一次?

更新:

我已经尝试使用锁和队列进行设置,但它不起作用.这就是我所拥有的:

# Globals - used to synch threads
waitingOnEvent = Queue.Queue
MainEvent = threading.Event()
MainEvent.clear()    # Not sure this is necessary, but figured I'd be safe
mainLock = threading.Lock()

def waitCall():
    mainLock.acquire()
    waitingOnEvent.put("waiting")
    mainLock.release()
    MainEvent.wait()
    waitingOnEvent.get(False)
    waitingOnEvent.task_done()
    #do stuff
    return

def triggerCall():
    mainLock.acquire()
    itemsinq = waitingOnEvent.qsize()
    MainEvent.set()
    waitingOnEvent.join()
    MainEvent.clear()
    mainLock.release()
    return
Run Code Online (Sandbox Code Playgroud)

itemsinq第一次正确反映了等待的呼叫数量,但只有第一个等待线程才能通过.从那时起,itemsinq始终为1,等待的线程轮流; 每次触发调用发生时,下一次触发.

更新2 似乎只有一个event.wait()线程正在唤醒,但queue.join()正在运行.这告诉我一个等待线程被唤醒,从队列中获取并调用task_done(),并且单个get()/ task_done()以某种方式清空队列并允许join().触发器线程然后完成join(),清除事件,从而防止其他等待线程通过.为什么只有一次get/task_done调用之后队列才会注册为空/完成?

只有一个似乎在醒来,即使我注释掉queue.get()和queue.task_done()并挂起触发器以便它无法清除事件.

Jas*_*rff 11

您不需要事件,也不需要锁定和队列.你需要的只是一个队列.

呼叫queue.put删除邮件而不等待邮件传递或处理.

调用queue.getworker线程等待消息到达.

import threading
import Queue

active_queues = []

class Worker(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.mailbox = Queue.Queue()
        active_queues.append(self.mailbox)

    def run(self):
        while True:
            data = self.mailbox.get()
            if data == 'shutdown':
                print self, 'shutting down'
                return
            print self, 'received a message:', data

    def stop(self):
        active_queues.remove(self.mailbox)
        self.mailbox.put("shutdown")
        self.join()


def broadcast_event(data):
    for q in active_queues:
        q.put(data)

t1 = Worker()
t2 = Worker()
t1.start()
t2.start()
broadcast_event("first event")
broadcast_event("second event")
broadcast_event("shutdown")

t1.stop()
t2.stop()
Run Code Online (Sandbox Code Playgroud)

消息不必是字符串; 它们可以是任何Python对象.