haskell - ¿Por qué no funciona el sueño?
ghc ffi (2)
El RTS de GHC parece utilizar señales para sus own purposes , lo que significa que no pasará mucho tiempo antes de que una de estas señales interrumpa el sueño. Tampoco creo que sea un error, el tiempo de ejecución viene con su propio territorio , por así decirlo. El enfoque haskelliano sería usar threadDelay
pero no es fácil para un programa C acceder a eso sin algunos trucos.
La forma correcta es reanudar repetidamente el sueño a pesar de las interrupciones de otras señales. Recomiendo usar nanosleep
ya que el sleep
solo tiene una precisión de segundos y las señales parecen ocurrir con mucha más frecuencia que eso.
#include <errno.h>
#include <time.h>
/* same as ''sleep'' except it doesn''t get interrupted by signals */
int keep_sleeping(unsigned long sec) {
struct timespec rem, req = { (time_t) sec, 0 }; /* warning: may overflow */
while ((rem.tv_sec || rem.tv_nsec) && nanosleep(&req, &rem)) {
if (errno != EINTR) /* this check is probably unnecessary */
return -1;
req = rem;
}
return 0;
}
¿Por qué c_sleep
regresa inmediatamente en el siguiente código?
{-# LANGUAGE ForeignFunctionInterface #-}
import Foreign.C.Types
import Data.Time.Clock
import Control.Concurrent
foreign import ccall unsafe "unistd.h sleep"
c_sleep :: CUInt -> IO CUInt
main :: IO ()
main = do
getCurrentTime >>= print . utctDayTime
c_sleep 10 >>= print -- this doesn''t sleep
getCurrentTime >>= print . utctDayTime
threadDelay $ 10 * 1000 * 1000 -- this does sleep
getCurrentTime >>= print . utctDayTime
$ ghc --make Sleep.hs && ./Sleep [1 of 1] Compiling Main ( Sleep.hs, Sleep.o ) Linking Sleep ... 29448.191603s 10 29448.20158s 29458.211402s $ ghc --version The Glorious Glasgow Haskell Compilation System, version 7.8.3 $ cabal --version cabal-install version 1.20.0.3 using version 1.20.0.0 of the Cabal library
Nota: En realidad, me gustaría usar el código de sleep
en código C para simular algunos cálculos pesados en una función de func
y llamar a esa función en Haskell, pero eso tampoco funciona, probablemente por las mismas razones.
Todas las primitivas de concurrencia siempre tienen una declaración de recuperación que pueden bloquear por menos tiempo que el especificado; pueden regresar falsamente. Esto no tiene nada que ver con el idioma, es la naturaleza de la concurrencia, por lo que si desea esperar exactamente la cantidad de tiempo especificada, en cualquier idioma que necesite construir un bucle que compruebe el reloj después de la suspensión.