Description
The I/O thread first takes the endpoint lock and then gets the consumer lock, the queue runner thread takes the consumer lock and then tries to get the endpoint lock.
By modifying the I/O thread to release the endpoint lock if it cannot get the consumer lock we can avoid the deadlock.