TQueue can lead to thread starvation
For background, please see this SO question
When using TQueue, a sufficiently fast/persistent writer can result in the reader never getting scheduled, causing the queue to continually grow and lost concurrency.
I believe the issue is caused by the definition of readTQueue:
readTQueue :: TQueue a -> STM a readTQueue (TQueue read write) = do xs <- readTVar read case xs of (x:xs') -> do writeTVar read xs' return x  -> do ys <- readTVar write case ys of  -> retry _ -> case reverse ys of  -> error "readTQueue" (z:zs) -> do writeTVar write  writeTVar read zs return z
Note that the last
case needs to traverse the write-end of the queue within the STM transaction. If the list is sufficiently large, a writer can commit a new transaction much more quickly, invalidating the read transaction. If threads continue to write to the queue, the reader will never get an opportunity to commit (and the list will grow, exacerbating the problem).
This alternative definition seems to fix the problem, but I don't know if there are other drawbacks to using it.
readTQueue' :: TQueue a -> STM a readTQueue' (TQueue read write) = do xs <- readTVar read case xs of (x:xs') -> do writeTVar read xs' return x  -> do ys <- readTVar write case ys of  -> retry _ -> do writeTVar write  let (z:zs) = reverse ys writeTVar read zs return z