[GHC] #9539: TQueue can lead to thread starvation

GHC ghc-devs at haskell.org
Mon Sep 1 23:52:14 UTC 2014


#9539: TQueue can lead to thread starvation
-------------------------------------+-------------------------------------
       Reporter:  jwlato             |                   Owner:
           Type:  bug                |                  Status:  new
       Priority:  normal             |               Milestone:
      Component:  libraries (other)  |                 Version:  7.8.2
       Keywords:  stm                |        Operating System:
   Architecture:  Unknown/Multiple   |  Unknown/Multiple
     Difficulty:  Unknown            |         Type of failure:
     Blocked By:                     |  None/Unknown
Related Tickets:                     |               Test Case:
                                     |                Blocking:
                                     |  Differential Revisions:
-------------------------------------+-------------------------------------
 For background, please see [http://stackoverflow.com/questions/25536604
 /huge-memory-consumption-for-simple-multithreaded-
 haskell/25560047#25560047 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
 }}}

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/9539>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list