2012-08-24 16 views
6

Tengo el siguiente código:comportamiento extraño con la concurrencia en Haskell

import Control.Concurrent 

sleepSort = mapM_ (forkIO . put) 
    where put x = threadDelay (x*10000) >> print x 

Esto realiza una especie de sueño en un conjunto de números enteros, y funciona bien, además de una advertencia:

el programa imprime cada uno de los números en el conjunto de datos en secuencia, tal como se supone que debe hacerlo. Sin embargo, después de que termine de imprimir el último número, espera a que el usuario ingrese un número, luego echos ese número y luego completa.

No creo que pida la opinión del usuario en ningún momento, entonces, ¿por qué sucede esto?

+0

¿Está utilizando GHCi? Si es así, ¿podría simplemente actuar de forma peculiar de una manera que parece como si fuera necesaria y luego echos un número? Si no, ¿cómo se ve tu 'main'? – gspr

+0

Si está intentando esto en GHCi, intente escribir 'print' como la entrada del usuario. – Vitus

Respuesta

7

Esto sucede porque el hilo principal no espera a que se completen los otros hilos. Su programa inicia n subprocesos, pero el subproceso principal se cierra inmediatamente y vuelve al intérprete de comandos. Mientras tanto, los otros hilos continúan produciendo de salida:

Prelude Control.Concurrent> sleepSort [1,2,3] 
1 
Prelude Control.Concurrent> 2 
3 

Puede solucionar este problema mediante la adición de un retraso en el hilo principal:

Prelude Control.Concurrent> sleepSort [1,2,3] >> threadDelay 10000 
1 
2 
3 

Si se ejecuta un programa compilado, sería simplemente salir inmediatamente sin imprimir nada:

$ cat Test.hs 
import Control.Concurrent 

sleepSort = mapM_ (forkIO . put) 
    where put x = threadDelay (x*1000) >> print x 

main = sleepSort [1,2,3] 
$ ghc --make -O2 Test.hs 
[1 of 1] Compiling Main    (Test.hs, Test.o) 
Linking Test ... 
$ ./Test 
$ 

actualización: en lugar de añadir una llamada a threadDelay a,784 mil, puede utilizar un semáforo en la función sleepSort:

import Control.Concurrent 
import Control.Concurrent.QSemN 

sleepSort l = do 
    qsem <- newQSemN 0 
    mapM_ (forkIO . put qsem) l 
    waitQSemN qsem n 
    where 
    n = length l 
    put qsem x = threadDelay (x*1000) >> print x >> signalQSemN qsem 1 

main = sleepSort [1,2,3] 
+0

¿Hay alguna manera simple de esperar a que se completen los otros subprocesos, o eso agrega mucha complejidad? –

+1

@BenjaminKovach Ver la actualización. –

+0

¡Muchas gracias! –

Cuestiones relacionadas