Note that we put the code to push the data onto the queue in a smaller scope, so we notify the condition variable after unlocking the mutex — this is so that if the waiting thread wakes immediately, it doesn't then have to block again, waiting for us to unlock the mutex.