2011-10-22 4 views
9

C'è un modo per aumentare un intervallo di tempo, in base al quale l'RTS decide che il thread si è bloccato indefinitamente in una transazione STM? Ecco il mio codice:Haskell: thread bloccato a tempo indeterminato in una transazione STM

import Control.Concurrent (ThreadId) 
import Control.Concurrent.MVar (MVar,newMVar,withMVar) 
import Control.Concurrent.STM 
import qualified Control.Concurrent.ThreadManager as TM 

data ThreadManager = ThreadManager { tmCounter::TVar Int, tmTM::MVar TM.ThreadManager } 

data Settings = Settings { 
    maxThreadsCount::Int } 

createThreadManager :: Settings -> IO ThreadManager 
createThreadManager s = do 
    counter <- atomically $ newTVar (maxThreadsCount s) 
    tm <- TM.make >>= newMVar 
    return $ ThreadManager counter tm 

forkManaged :: ThreadManager -> IO() -> IO ThreadId 
forkManaged tm fn = do 
    atomically $ do 
     counter <- readTVar $ tmCounter tm 
     check $ counter > 0 
     writeTVar (tmCounter tm) (counter - 1) 
    withMVar (tmTM tm) $ \thrdmgr -> TM.fork thrdmgr $ do 
     fn 
     atomically $ do 
      counter <- readTVar $ tmCounter tm 
      writeTVar (tmCounter tm) (counter + 1) 

forkManaged fa in modo che quantità di esecuzione contemporaneamente thread gestiti non superi maxThreadsCount. Funziona bene fino a carichi pesanti. Sotto carico pesante RTS genera un'eccezione. Penso che sotto carico pesante, sulla concorrenza concomitante per le risorse, alcuni thread non abbiano tempo per accedere al contesto STM. Quindi penso che aumentare l'intervallo di tempo quando RTS decide di lanciare questa eccezione può risolvere il problema.

+4

Sei sicuro che la decisione sia presa con i timeout? Ho pensato che usasse i suoi registri per decidere quando due 'retry' si stavano aspettando a vicenda. –

+0

@ Daniel: Daniel, ho aggiornato la domanda fornendo il mio codice usando STM. Questo è il motivo per cui penso al problema con il timeout. –

+0

È possibile che 'fn' stia lanciando un'eccezione e impedendo l'incremento del contatore? –

risposta

7

Daniel Wagner ha ragione. La decisione non è presa con i timeout. Il codice rilevante nei rts è Schedule.c

Vedere la funzione resurrectThreads per cui viene generata l'eccezione. Il commento descrive che questo è solo gettato su thread trovati per essere spazzatura dopo GC. ezyang ha descritto come questo ha lavorato per mvars: http://blog.ezyang.com/2011/07/blockedindefinitelyonmvar/

[male speculazione riguardante check rimossi quando ho controllato la sua fonte e si rese conto che era solo una semplice guardia/riprovare e non ciò che è stato descritto in un precedente lavoro - oops! Ora sospetto che Daniel Wagner sia corretto anche qui, e il problema è in qualche modo che il contatore non viene incrementato.]

+0

Sclv, Daniel, grazie per la risposta, in particolare per i link utili all'implementazione di rts di ghc! Controllerò il mio codice ancora una volta. –