2015-02-03 2 views
16

c_sleep이 다음 코드에서 즉시 반환되는 이유는 무엇입니까?왜 잠자기가 작동하지 않습니까?

{-# 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 

참고 : 사실, 나는 함수 func에 몇 가지 무거운 계산을 시뮬레이션하고 하스켈에 함수를 호출하는 C 코드에서 sleep를 사용하고 싶지만, 그 중 하나가 작동하지 않습니다 아마 같은 이유로.

+1

GHC 런타임이 'sleep'을 방해하는 신호를 사용하고있을 가능성이 있습니다. 오류 코드를 확인 했습니까? 아마도 인터럽트가 발생하면 루프를 다시 시작하여 다시 시작해야합니다 (이 경우 더 높은 정밀도를 위해 'nanosleep'을 사용하는 것이 가장 좋습니다). – Rufflewind

+1

@Rufflewind :'sleep'은 오류 코드를 반환하지 않지만 초 단위의 해제 가능량은 /입니다. '나노 슬립 (nanosleep) '을 아직 시도하지 않았지만'휴면 (usleep) '도 작동하지 않습니다. – Zeta

+0

오류 코드는'errno' 변수를 통해 "반환"됩니다. 'throwErrnoIf (/ = 0) "sleep"'안에'(c_sleep 10)'을 감싸면 중단되는 것을 볼 수 있습니다. – Rufflewind

답변

12

GHC의 ownpurposes의 경우, 이는 이러한 신호 중 하나에 의해 절전이 중단되기 전에 오래 걸리지 않는다는 것을 의미합니다. 나는 버그라고 생각하지 않는다. 런타임은 말하자면 come with its own territory이다. 하스켈 법은 threadDelay을 사용하는 것이지만 C 프로그램이 약간의 속임수없이이를 액세스하는 것은 쉽지 않습니다.

proper way은 다른 신호의 중단에도 불구하고 반복적으로 수면을 재개합니다. sleep의 정밀도는 초 단위이고 신호는 그보다 훨씬 자주 발생하는 것처럼 보일 수 있으므로 nanosleep을 사용하는 것이 좋습니다.

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

모든 동시성 프리미티브에는 항상 지정된 시간보다 짧은 시간 동안 차단할 수있는 clawback 문이 있습니다. 이들은 거짓으로 반환 될 수 있습니다. 이것은 언어와 관련이 없으며 동시성의 특성이므로 지정된 시간 동안 기다리고 싶으면 어떤 언어로든 잠자기 후 시계를 확인하는 루프를 만들어야합니다.

+0

이것이 사실이라면, 일반적으로 단일 스레드 C 도메인에서 호출 직후에 인터럽트가 발생하는 유효한'(u) sleep() '호출을 기대하지 않을 것입니다. 만약 하나가'-threaded '및/또는 동시성을 사용하지 않는다면 더욱 그렇다. – Zeta

+0

@ Zeta 기대가 잘못되었습니다. 아무도 허위 모닝콜에 대한 이유를 밝히지 않습니다. 응용 프로그램이 스스로를 인터럽트했기 때문에''일어나기 만 할 것 "이라고 말하지 않습니다. 나는 명시되지 않은 행동에 대해 직관적으로 코드를 작성하는 것이 타당하지 않다고 생각합니다. 예를 들어 C에서 초기화되지 않은'int'가 0이라고 가정하지 않습니다. –