2015-02-03 12 views
16

Tại sao c_sleep trả lại ngay trong mã sau?Tại sao không ngủ?

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

Lưu ý: Thực ra, tôi muốn sử dụng sleep trong mã C để mô phỏng một số tính toán nặng trong một hàm func và gọi rằng chức năng trong Haskell, nhưng điều đó không làm việc, hoặc , có lẽ vì những lý do tương tự.

+1

Có thể thời gian chạy GHC đang sử dụng tín hiệu làm gián đoạn 'ngủ'. Bạn đã kiểm tra mã lỗi chưa? Có lẽ bạn nên quấn nó trong một vòng lặp để khởi động lại nó nếu nó bị gián đoạn (trong trường hợp đó tốt nhất là sử dụng 'nanosleep' để có độ chính xác cao hơn). – Rufflewind

+1

@Rufflewind: 'sleep' không trả lại mã lỗi, nhưng số tiền không được trả trong vài giây: /. Chưa thử 'nanosleep', nhưng' usleep' cũng không hoạt động. – Zeta

+0

Mã lỗi được "trả về" thông qua biến 'errno'. Wrap '(c_sleep 10)' bên trong 'throwErrnoIf (/ = 0)" sleep "' và bạn sẽ thấy rằng nó đang bị gián đoạn. – Rufflewind

Trả lời

12

GHC's RTS appears to use signals cho ownpurposes, điều này có nghĩa là sẽ không lâu sau khi một giấc ngủ bị gián đoạn bởi một trong các tín hiệu này. Tôi không nghĩ rằng đó là một lỗi, thời gian chạy không come with its own territory, do đó, để nói chuyện. Cách tiếp cận Haskellian sẽ là sử dụng threadDelay nhưng nó không dễ dàng cho một chương trình C để truy cập mà không có một số trickery.

proper way liên tục tiếp tục ngủ mặc dù bị gián đoạn từ các tín hiệu khác. Tôi khuyên bạn nên sử dụng nanosleepsleep chỉ có độ chính xác là giây và tín hiệu xuất hiện thường xuyên hơn nhiều.

#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

Tất cả nguyên thủy đồng thời luôn luôn có một tuyên bố clawback rằng họ có thể cản trở cho ít thời gian hơn so với quy định - họ có thể trở lại spuriously. Điều này là không có gì để làm với ngôn ngữ, nó là bản chất của đồng thời, vì vậy nếu bạn muốn chờ đợi chính xác số lượng thời gian quy định, trong bất kỳ ngôn ngữ nào bạn cần để xây dựng một vòng kiểm tra đồng hồ sau khi ngủ.

+0

Trong khi điều này là đúng, người ta sẽ không mong đợi một cuộc gọi '(u) sleep()' hợp lệ thường hoạt động tốt trong miền đơn của nó C để bị gián đoạn ngay lập tức sau cuộc gọi_. Thậm chí nhiều hơn như vậy nếu một người không sử dụng '-readed' và/hoặc concurrency. – Zeta

+0

@Zeta Kỳ vọng là sai rồi. Không ai xác định lý do cho việc đánh thức giả mạo - nó là _spurious_; nó không nói '" có thể thức dậy * chỉ * bởi vì ứng dụng bị gián đoạn chính nó "'. Tôi không nghĩ rằng nó có ý nghĩa để mã trực giác chống lại hành vi không xác định - như chúng tôi không giả định một uninitialized 'int' là số không trong C. –

Các vấn đề liên quan