I am creating a Sound
class to play notes and would like feedback on the correctness and conciseness of my design. This class differs from the typical consumer/producer in two ways:
The consumer should respond to events, such as to shut down the thread, or otherwise continue forever. The typical consumer/producer exits when the queue is empty. For example, a thread waiting in
queue.get
cannot handle additional notifications.Each set of notes submitted by the producer should overwrite any unprocessed notes remaining on the queue.
Originally I had the consumer process one note at a time using the queue
module. I found continually acquiring and releasing the lock without any competition to be inefficient, and as previously noted, queue.get
prevents waiting on additional events. So instead of building upon that, I rewrote it into:
import threading
queue = []
condition = threading.Condition()
interrupt = threading.Event()
stop = threading.Event()
def producer():
while some_condition:
ns = get_notes() # [(float,float)]
with condition:
queue.clear()
queue.append(ns)
interrupt.set()
condition.notify()
with condition:
stop.set()
condition.notify()
consumer.join()
def consumer():
while not stop.is_set():
with condition:
while not (queue or stop.is_set()):
condition.wait()
if stop.is_set():
break
interrupt.clear()
ns = queue.pop()
ss = gen_samples(ns) # iterator/fast
for b in grouper(ss, size/2):
if interrupt.is_set() or stop.is_set()
break
stream.write(b)
thread = threading.Thread(target=consumer)
thread.start()
producer()
My questions are as follows:
Is this thread-safe? I want to specifically point out my use of
is_set
without locks or synchronization (in the for-loop).Can the events be replaced with boolean variables? I believe so as conflicting writes in both threads (data race) are guarded by the
condition
variable. There is a race condition between setting and checking events but I do not believe it affects program flow.Is there a more efficient approach/algorithm utilizing different synchronization primitives from the
threading
module?
edit: Found and fixed a possible deadlock described in Why does Python threading.Condition() notify() require a lock?