2015-02-03 6 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 

नोट: वास्तव में, मैं सी कोड में sleep उपयोग करने के लिए एक समारोह func में कुछ भारी गणना अनुकरण और हास्केल में फोन कि समारोह चाहते हैं, लेकिन है कि या तो काम नहीं करता है , शायद इसी कारण से।

+1

यह संभव है कि जीएचसी रनटाइम सिग्नल का उपयोग कर रहा है जो 'नींद' को बाधित करता है। क्या आपने त्रुटि कोड की जांच की है? शायद इसे लूप में लपेटना चाहिए यदि इसे बाधित हो जाता है (जिस स्थिति में उच्च परिशुद्धता के लिए 'नैनोस्ली' का उपयोग करना सबसे अच्छा होता है)। – Rufflewind

+1

@Rufflewind: 'नींद' एक त्रुटि कोड नहीं लौटाता है, लेकिन सेकंड में अनसुलझा राशि: /। अभी तक 'नैनोस्ली' की कोशिश नहीं की है, लेकिन 'नींद' या तो काम नहीं करता है। – Zeta

+0

त्रुटि कोड 'errno' चर के माध्यम से "वापस" है। लपेटें '(c_sleep 10) 'throwErrnoIf (/ = 0)" नींद "के अंदर' और आप देखेंगे कि यह बाधित हो रहा है। – Rufflewind

उत्तर

12

जीएचसी के RTS appears to use signals अपने ownpurposes के लिए, जिसका अर्थ यह है कि इन संकेतों में से किसी एक द्वारा नींद में बाधा आने से बहुत पहले नहीं होगा। मुझे नहीं लगता कि यह एक बग है, रनटाइम come with its own territory करता है, इसलिए बोलने के लिए। हास्केलियन दृष्टिकोण threadDelay का उपयोग करना होगा, लेकिन सी प्रोग्राम के लिए कुछ ट्रिकरी के बिना इसे एक्सेस करना आसान नहीं है।

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

हालांकि यह सच है, कोई वैध '(u) नींद() 'कॉल की अपेक्षा नहीं करेगा जो आमतौर पर कॉल_ के तुरंत बाद बाधित होने के लिए अपने एकल थ्रेड सी डोमेन में अच्छी तरह से काम करता है। और भी अधिक अगर किसी ने 'थ्रेड' और/या समरूपता का उपयोग नहीं किया है। – Zeta

+0

@Zeta उम्मीद तो गलत है। कोई भी कभी भी नकली जागरूकता के कारण को निर्दिष्ट नहीं करता है - यह _spurious_ है; यह नहीं कहता है कि "केवल * जाग सकता है * क्योंकि एप्लिकेशन ने खुद को बाधित कर दिया"। मुझे नहीं लगता कि यह अनिश्चित व्यवहार के खिलाफ सहजता से कोड को समझ में आता है - जैसे कि हम मानते हैं कि एक अनियमित 'int' शून्य में शून्य है। –

संबंधित मुद्दे