Frage Warum schläft nicht arbeiten?


Warum tut c_sleep zurück sofort in den folgenden Code?

{-# 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] Kompilieren Haupt (Sleep.hs, Sleep.o)
Schlaf verknüpfen ...
29448.191603s
10
29448,20158s
29458,211402s

$ ghc --Version
Das Glorious Glasgow Haskell Compilation System, Version 7.8.3

$ Kabale - Version
cabal-install Version 1.20.0.3
Verwendung der Version 1.20.0.0 der Cabal-Bibliothek

Hinweis: Eigentlich würde ich gerne verwenden sleep im C-Code, um einige schwere Berechnungen in einer Funktion zu simulieren func und Ruf an Das Funktion in Haskell, aber das funktioniert auch nicht, wahrscheinlich aus den gleichen Gründen.


16
2018-02-03 08:19


Ursprung


Antworten:


GHCs RTS scheint Signale zu verwenden für seine besitzen  ZweckeDas heißt, es wird nicht lange dauern, bis ein Schlaf durch eines dieser Signale unterbrochen wird. Ich glaube auch nicht, dass es ein Bug ist, die Laufzeit tut es mit einem eigenen Territorium kommen, sozusagen. Der Haskellsche Ansatz wäre zu verwenden threadDelay aber für ein C-Programm ist es nicht einfach, ohne Tricks darauf zuzugreifen.

Das richtige Weg ist es, den Schlaf trotz Unterbrechungen durch andere Signale wiederholt fortzusetzen. Ich empfehle die Verwendung nanosleep schon seit sleep hat nur eine Genauigkeit von Sekunden und die Signale scheinen viel häufiger zu erscheinen.

#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;
}

12
2018-02-03 08:53



Alle Concurrency-Primitive haben immer eine Clawback-Anweisung, die sie für weniger Zeit blockieren können als angegeben - sie können fälschlicherweise zurückkehren. Dies hat nichts mit der Sprache zu tun, sondern mit der Art der Parallelität. Wenn Sie also genau auf die angegebene Zeit warten möchten, müssen Sie in jeder Sprache eine Schleife erstellen, die die Uhr nach dem Schlaf überprüft.


1
2018-02-03 13:08