Example of protecting resource access using a condition, like I said in comments.
import collections
import threading
import time
queue = collections.deque()
condition = threading.Condition()
def consumer():
condition.acquire()
while True:
while queue:
item = queue.popleft()
condition.release()
# do something with item
print(item)
condition.acquire()
condition.wait()
def push_item(item):
with condition:
queue.append(item)
condition.notify()
# From that point forward, it is just demonstration code to show how to use
def example_producer_thread(*args):
for arg in args:
push_item(arg)
consumer_thread = threading.Thread(target=consumer, name='queue consumer')
consumer_thread.daemon = True # so it does not prevent python from exiting
consumer_thread.start()
for example in [range(0, 10), range(10, 20), range(20, 30)]:
threading.Thread(target=example_producer_thread, args=example).start()
time.sleep(1) # let the consumer thread some time before the script gets killed
The core is here:
consumer()
is a consumer thread, it remains idle (no polling) until some other thread puts items in the queue. When awoken, it will lock the queue, get an item, unlock the queue, process the item, until there is no more items in the queue. It then releases it and goes back to sleep.
push_item()
pushes a single item in the queue, and notifies the consumer thread it should wake up.
The rest is just to make it a working example. example_producer_thread
will simply push its arguments into the queue. And we start three of those, each operating on a range of numbers so we can see the results.
Simply add a maxlen
to the queue and you're good to go. Perhaps encapsulate the functionality in a small class while you're at it.