OCaml

2012-05-29 14 views
8

में थ्रेड विलंब और कीबोर्ड ईवेंट ओकैमल में एक साधारण गेम लूप है। राज्य प्रदर्शित होता है, इनपुट प्राप्त होता है, और राज्य उन्नत है। प्रत्येक लूप 0.025 सेकेंड के लिए थ्रेड में देरी करके प्रति सेकंड फ्रेम की संख्या 40 से कम होती है।OCaml

main.ml:

let rec main (* state *) frame_time = 
    (* Display state here. *) 
    Input.get_input(); 
    (* Advance state by one frame here. *) 
    (* If less than 25ms have passed, delay until they have. *) 
    if((Sys.time()) < (frame_time +. 0.025)) then 
    Thread.delay ((frame_time +. 0.025) -. (Sys.time())); 
    main (* next_state *) (Sys.time()) 
;; 

let init = 
    Graphics.open_graph " 800x500"; 
    let start_time = (Sys.time()) in 
    main (* start_state *) start_time 
;; 

इस उदाहरण के लिए, get_input समारोह बस खिड़की के कीस्ट्रोक्स प्रिंट करता है।

input.ml: आसान परीक्षण के लिए

let get_input() = 
    let s = Graphics.wait_next_event 
    [Graphics.Key_pressed] in 
    if s.Graphics.keypressed then 
    Graphics.draw_char s.Graphics.key 
;; 

Makefile:

main: input.cmo main.cmo 
    ocamlfind ocamlc -o [email protected] unix.cma -thread threads.cma graphics.cma $^ 
main.cmo: main.ml 
    ocamlfind ocamlc -c $< -thread 
input.cmo: input.ml 
    ocamlfind ocamlc -c $< 

यह सबसे अधिक भाग के लिए काम करता है, लेकिन जब कुंजी बहुत जल्दी दबाया जाता है, कार्यक्रम इस त्रुटि के साथ दुर्घटनाओं:

Fatal error: exception Unix.Unix_error(2, "select", "")

मेरा मानना ​​है कि इसमें कुछ है Thread.delay के साथ करने के लिए। इस मुद्दे का कारण क्या है, और निरंतर एफपीएस प्राप्त करने का सबसे अच्छा तरीका क्या है?

उत्तर

9

मुझे बिल्कुल यकीन नहीं है कि क्या हो रहा है (यह Thread.delay के कार्यान्वयन पर निर्भर करता है, जिसे मैं नहीं जानता)। हालांकि, त्रुटि 2 Unix.EAGAIN है, जो कर्नेल संसाधनों की अस्थायी कमी का प्रतिनिधित्व करता है। जैसा कि नाम कहता है, आपको शायद अपने थ्रेड डेल को फिर से करने का प्रयास करना चाहिए। यदि मैं Unix.Unix_error अपवाद को पकड़ने के लिए try ... with का उपयोग करता हूं तो मुझे EAGAIN वितरित किए जाने के अलावा कोई अन्य त्रुटियां नहीं दिखाई देती हैं। अगर मैं सिर्फ एक संदेश प्रिंट करता हूं और जारी रखता हूं, तो प्रोग्राम काम करता प्रतीत होता है। कम से कम, यह खिड़की के पात्रों को गूंजना जारी रखता है और क्रैश नहीं होता है। मैं ओएस एक्स 10.7 (शेर) में काम कर रहा हूं। यह आपके लिए अलग-अलग काम कर सकता है।

संपादित

इस कोड के साथ एक अन्य संभावित समस्या यह है कि Sys.time() रिटर्न प्रोसेसर समय है, जो केवल बढ़ जाती है, जबकि प्रक्रिया वास्तविक गणना कर रही है। यह प्रक्रिया में वृद्धि नहीं होती है जबकि प्रक्रिया इनपुट के लिए इंतजार कर रही है। इसका मतलब यह है कि देरी हमेशा लागू होती है, भले ही आप कीप्रेस के बीच लंबे समय तक प्रतीक्षा करें (यह मुझे थोड़ी देर के लिए भ्रमित कर रहा था)। Unix.gettimeofday() का उपयोग करना बेहतर हो सकता है, जो दीवार घड़ी का समय देता है।

संपादित 2

कुछ और अनुसंधान और परीक्षण के बाद, मुझे विश्वास है कि Unix.EAGAIN त्रुटि आप कह रहा है कि पूर्ण देरी किसी घटना से बाधित था। आपके मामले में बाधा घटना एक चरित्र का आगमन है (मुझे विश्वास है)। इसलिए यदि आप पूर्ण समय का इंतजार करना चाहते हैं, तो आपको एक कॉल को Thread.delay() पर लूप के साथ प्रतिस्थापित करना चाहिए।

यह आप अपने मुख्य कोड के लिए निम्नलिखित की तरह कुछ देता है:

let rec main (* state *) frame_time = 
    (* Display state here. *) 
    Input.get_input(); 
    (* Advance state by one frame here. *) 
    (* If less than 25ms have passed, delay until they have. *) 
    let rec delay() = 
    let duration = frame_time +. 0.025 -. Unix.gettimeofday() in 
    if duration > 0.0 then 
     try 
     Thread.delay duration 
     with Unix.Unix_error (Unix.EAGAIN, _, _) -> delay() 
    in 
    delay(); 
    main (* next_state *) (Unix.gettimeofday ()) 
;; 

let init = 
    Graphics.open_graph " 800x500"; 
    let start_time = (Unix.gettimeofday ()) in 
    main (* start_state *) start_time 
;; 

(यदि आप अपने देरी करने के लिए Unix.select उपयोग करते हैं, आप धागे पर निर्भरता को हटा सकते हैं लेकिन आप के लिए उन्हें वैसे भी जरूरत हो सकती है। अन्य कारणों से। कोड को समान दिखाई देगा, सिवाय इसके कि त्रुटि EAGAIN की बजाय EINTR है।)

+2

जेफ़री सभी खातों पर सही है। आप थ्रेड के बारे में अधिक जानकारी प्राप्त कर सकते हैं।देरी [यहां] (http://ocamlunix.forge.ocamlcore.org/threads.html#htoc63)। –

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