This is either a feature or nonfeature, depending on your program—it allows spawned
worker threads to finish their tasks in the absence of join calls or sleeps, but it can
prevent programs like the one in Example 5-14 from shutting down when they wish.
To make this example work with threading, use the following alternative code (see
queuetest3.py in the examples tree for a complete version of this, as well as thread-count-
threading.py, also in the tree, for a case where this refusal to exit can come in handy):
import threading, queue, time
def producer(idnum, dataqueue): ...
def consumer(idnum, dataqueue): ...
if __name__ == '__main__':
for i in range(numconsumers):
thread = threading.Thread(target=consumer, args=(i, dataQueue))
thread.daemon = True # else cannot exit!
thread.start()
waitfor = []
for i in range(numproducers):
thread = threading.Thread(target=producer, args=(i, dataQueue))
waitfor.append(thread)
thread.start()
for thread in waitfor: thread.join() # or time.sleep() long enough here
print('Main thread exit.')
We’ll revisit the daemons and exits issue in Chapter 10 while studying GUIs; as we’ll
see, it’s no different in that context, except that the main thread is usually the GUI itself.
Running the script
Now, as coded in Example 5-14, the following is the output of this example when run
on my Windows machine. Notice that even though the queue automatically coordi-
nates the communication of data between the threads, this script still must use a lock
to manually synchronize access to the standard output stream; queues synchronize data
passing, but some programs may still need to use locks for other purposes. As in prior
examples, if the safeprint lock is not used, the printed lines from one consumer may
be intermixed with those of another. It is not impossible that a consumer may be paused
in the middle of a print operation:
C:\...\PP4E\System\Threads> queuetest.py
consumer 1 got => [producer id=0, count=0]
consumer 0 got => [producer id=0, count=1]
consumer 1 got => [producer id=0, count=2]
consumer 0 got => [producer id=0, count=3]
consumer 1 got => [producer id=1, count=0]
consumer 1 got => [producer id=2, count=0]
consumer 0 got => [producer id=1, count=1]
consumer 1 got => [producer id=3, count=0]
consumer 0 got => [producer id=1, count=2]
Threads | 207