Fix destroying threads with tasks in queue

The previous code could make the worker thread exit without finishing
all work in the queue. With this modification we make sure the queue is
empty before exiting all worker threads. Moreover, the main thread will
wait for all worker threads when try to join them all, assuring all work
is done before exiting.