2012-08-30 7 views
5

Con el fin de familiarizarse con STM en Haskell, escribí la siguiente solución al problema de la cena de los filósofos:¿Qué pasa con la siguiente solución para los "Filósofos del comedor"?

import Control.Concurrent 
import Control.Concurrent.STM 
import Control.Monad 
import System.Random 

type Fork = TVar Bool 
type StringBuffer = TChan String 

philosopherNames :: [String] 
philosopherNames = map show ([1..] :: [Int]) 

logThinking :: String -> StringBuffer -> STM() 
logThinking name buffer = writeTChan buffer $ name ++ " is thinking..." 

logEating :: String -> StringBuffer -> STM() 
logEating name buffer = writeTChan buffer $ name ++ " is eating..." 

firstLogEntry :: StringBuffer -> STM String 
firstLogEntry buffer = do empty <- isEmptyTChan buffer 
          if empty then retry 
            else readTChan buffer 

takeForks :: Fork -> Fork -> STM() 
takeForks left right = do leftUsed <- readTVar left 
          rightUsed <- readTVar right 
          if leftUsed || rightUsed 
          then retry 
          else do writeTVar left True 
            writeTVar right True 

putForks :: Fork -> Fork -> STM() 
putForks left right = do writeTVar left False 
         writeTVar right False 

philosopher :: String -> StringBuffer -> Fork -> Fork -> IO() 
philosopher name out left right = do atomically $ logThinking name out 
            randomDelay 
            atomically $ takeForks left right 
            atomically $ logEating name out 
            randomDelay 
            atomically $ putForks left right 

randomDelay :: IO() 
randomDelay = do delay <- getStdRandom(randomR (1,3)) 
       threadDelay (delay * 1000000) 

main :: IO() 
main = do let n = 8 
      forks <- replicateM n $ newTVarIO False 
      buffer <- newTChanIO 
      forM_ [0 .. n - 1] $ \i -> 
       do let left = forks !! i 
        right = forks !! ((i + 1) `mod` n) 
        name = philosopherNames !! i 
       forkIO $ forever $ philosopher name buffer left right 

      forever $ do str <- atomically $ firstLogEntry buffer 
         putStrLn str 

Cuando compilar y ejecutar mi solución, parece que no hay problemas de concurrencia obvias existir: Cada filósofo eventualmente comen y ningún filósofo parece ser favorecido. Sin embargo, si quito las declaraciones de randomDelayphilosopher, compilar y ejecutar, la salida de mi programa tiene el siguiente aspecto:

1 is thinking... 
1 is eating... 
1 is thinking... 
1 is eating... 
2 is thinking... 
2 is eating... 
2 is thinking... 
2 is eating... 
2 is thinking... 
2 is eating... 
2 is thinking... 

About 2500 lines later... 

2 is thinking... 
2 is eating... 
2 is thinking... 
3 is thinking... 
3 is eating... 
3 is thinking... 
3 is eating... 

And so on... 

lo que sucede en este caso?

+0

Si esto es tarea, por favor agregue la pestaña de tarea. – Gray

+0

No es tarea, leo acerca de STM en Real World Haskell y estoy tratando de familiarizarme con esto. – Alexandros

+0

con mi configuración (Debian 6 Testing, ghc 7.4.1, runhaskell/ghc -O2 --make philosophers.hs) No creo que tenga un problema: los filósofos 1 ..8 están comiendo y pensando cada uno en su turno. ¿Cuál es su versión ghc y está compilando o utilizando ghci? – epsilonhalbe

Respuesta

5

Se necesita compilar con el tiempo de ejecución roscada y habilitado rtsopts, y ejecutarlo con +RTS -N (o +RTS -Nk donde k es el número de hilos. Con eso, me da una salida como

8 is eating... 
6 is eating... 
4 is thinking... 
6 is thinking... 
4 is eating... 
7 is eating... 
8 is thinking... 
4 is thinking... 
7 is thinking... 
8 is eating... 
4 is eating... 
4 is thinking... 
4 is eating... 
6 is eating... 
4 is thinking... 

El punto es para que otro filósofo piense/coma, debe ocurrir un cambio de contexto si no tiene varios hilos de hardware a su disposición. Este cambio de contexto no suele ocurrir muy a menudo aquí, donde no se realiza mucha asignación, por lo que cada filósofo tiene mucho tiempo para pensar y comer mucho antes de que aparezca el siguiente turno.

Con suficientes hilos a su disposición, todos los filósofos pueden simultáneamente intentar alcanzar las horquillas.

+0

Con '+ RTS -N9' (8 hilos para cada filósofo y 1 para el hilo principal, que escribe en' stdout'), parece que dos filósofos están monopolizando la CPU durante un período de tiempo específico. – Alexandros

+4

¿Cuántos núcleos tienes? No puede haber más hilos ejecutándose al mismo tiempo que capacidades de hardware, por lo que si tiene una máquina de doble núcleo, no más de dos filósofos pueden competir por las horquillas en cualquier momento. –

+0

Es mejor pensar en '-Nk' como controlar el número de núcleos a usar en lugar de la cantidad de subprocesos del sistema operativo. Entre otros casos, esto importa si usa 'forkOS' o realiza llamadas FFI. –

Cuestiones relacionadas