2015-06-17 9 views
7

मैं कई एमवीआर का उपयोग करते समय किसी समस्या को डीबग करने का प्रयास कर रहा हूं, हालांकि कोई किस्मत नहीं।थ्रेड किसी एमवीआर ऑपरेशन में अनिश्चित काल तक अवरुद्ध

मेरा कोड दो एमवीआर का उपयोग करता है: एक सर्वर वर्तमान स्थिति को स्टोर करने के लिए, और दूसरा क्लाइंट थ्रेड से नेटवर्क ईवेंट को पास करने के लिए। हालांकि कई बार कनेक्ट करने और डिस्कनेक्ट करने के बाद, सर्वर नए क्लाइंट कनेक्ट करने पर डेटा भेजना बंद कर देता है (संभवतः क्योंकि नेटवर्क इवेंट्स एमवीआर किसी भी कारण से खाली हो जाता है) और अंततः त्रुटि के साथ भ्रमण करता है: *** Exception: thread blocked indefinitely in an MVar operation

मैंने कोशिश करने में निम्नलिखित निष्कर्ष निकाला है पिछले कुछ दिनों में इस मुद्दे को डिबग करने के लिए:

  1. MVAr (रों) संशोधित करने के लिए इस्तेमाल किया कार्यों अभ्यस्त अपवाद
  2. फेंक समस्या एक ग्राहक जब तक या तो जोड़ता है, या तो डिस्कनेक्ट जोड़ता
  3. नहीं होती है ऐसा लगता है कि यह मुद्दा चलाया गया है domly (कभी कभी कई ग्राहकों तो डिस्कनेक्ट कनेक्ट कर सकते हैं, दूसरी बार इसे तुरंत होता है)

मैं तीन फाइलों को समस्या अलग-थलग कर दिया है:

  1. https://github.com/Mattiemus/IMC-Server/blob/master/IMC.hs (अपवाद sense में फेंक दिया जाता है)
  2. https://github.com/Mattiemus/IMC-Server/blob/master/IMC/Networking/Server.hs
  3. https://github.com/Mattiemus/IMC-Server/blob/master/IMC/Utilities/Concurrency.hs (कार्य करता है जो धक्का और एक MVAr में जमा एक सूची में पॉप)
  4. 012 ( application handleClient, और cleanupClient भीतर Modifined)

मैं पूरी तरह विचारों से बाहर हूँ, के रूप में मैं केवल का उपयोग modifyMVar और withMVar (ताकि निश्चित रूप से यह पूरी तरह से खाली कभी नहीं छोड़ा जाना चाहिए) - मेरे केवल धारणा है कि हो सकता है एक अपवाद MVAr को संशोधित करते हुए फेंक दिया जा रहा है, फिर भी मुझे लगता है कि यह बेहद असंभव है।

किसी भी मदद की सराहना की जाती है, यह समस्या मुझे कुछ समय के लिए परेशान कर रही है।

+1

मुझे नहीं लगता कि ज्यादातर लोगों को इस बग को खोजने के लिए इतना कोड के माध्यम से खोज करने के लिए चाहते हैं। शायद कुछ परीक्षण लिखने से आपको यह ढूंढने में मदद मिलेगी। – user2407038

+0

मैंने 4 मुख्य कार्यों में समस्या को और पिन करने के लिए प्रश्न को संशोधित किया है। इस समस्या को अलग करने के लिए मुझे किस प्रकार के परीक्षण लिखने की आवश्यकता होगी, समस्या अंततः मौसम के बावजूद होती है, मैं सर्वर या घटनाओं एमवीआर पर सभी संशोधकों को हटा देता हूं, जिससे मुझे विश्वास होता है कि मैं उन्हें गलत तरीके से उपयोग कर रहा हूं। घटनाओं पर कई उत्पादक हैं एमवीआर (प्रत्येक ग्राहक के लिए एक धागा) हालांकि केवल एक उपभोक्ता - शायद यह मुद्दा है? – Mattiemus

+0

'समझ' में आप एक चैनल की तरह 'MVar' का उपयोग कर रहे हैं। इसके बजाए 'चैन' का उपयोग क्यों न करें? –

उत्तर

4

तीन दिन बाद और इसका हल: वास्तव में नेटवर्किंग या समवर्ती कोड से संबंधित नहीं था, और वास्तव में नेटवायर में याम्पस dpSwitch के गलत गलत कार्यान्वयन के कारण असर पड़ा। सही कोड इस समारोह को लागू करने के इच्छुक किसी के लिए नीचे दिए गए पोस्ट:

dpSwitch :: (Monoid e, Applicative m, Monad m, T.Traversable col) => (forall wire. a -> col wire -> col (b, wire)) 
    -> col (Wire s e m b c) 
    -> Wire s e m (a, col c) (Event d) 
    -> (col (Wire s e m b c) -> d -> Wire s e m a (col c)) 
    -> Wire s e m a (col c) 
dpSwitch route wireCol switchEvtGen continuation = WGen $ gen wireCol switchEvtGen 
where 
    gen wires switchEvtGenWire _ (Left x) = return (Left mempty, WGen $ gen wires switchEvtGenWire) 
    gen wires switchEvtGenWire ws (Right x) = do    
     let routings = route x wires 
     wireSteps <- T.sequenceA (fmap (\(wireInput, wire) -> stepWire wire ws (Right wireInput)) routings) 
     let wireOutputs = T.sequenceA (fmap fst wireSteps) 
      steppedWires = fmap snd wireSteps 
     case wireOutputs of 
      Left wireInhibitedOutput -> return (Left wireInhibitedOutput, WGen $ gen steppedWires switchEvtGenWire) 
      Right wireResultOutput -> do 
       (event, steppedSwitchEvtGenWire) <- stepWire switchEvtGenWire ws (Right (x, wireResultOutput)) 
       case event of 
        Left eventInhibited -> return (Left eventInhibited, WGen $ gen steppedWires steppedSwitchEvtGenWire) 
        Right NoEvent -> return (wireOutputs, WGen $ gen steppedWires steppedSwitchEvtGenWire) 
        Right (Event e) -> return (wireOutputs, continuation steppedWires e) 
2

मुझे लगता है कि मुझे समस्या दिखाई दे रही है - यह Server.hs में है। आपके पास ऐसे ऑपरेशन हैं जो withMVar कॉल के अंदर नेटवर्क IO करते हैं। अब कल्पना करें कि आईओ प्रभावी रूप से हमेशा के लिए ब्लॉक करता है। आपको न तो एक अपवाद मिलता है जो var को प्रतिस्थापित करने के लिए मजबूर करता है, न ही ऑपरेशन सामान्य रूप से पूर्ण होता है और var को प्रतिस्थापित करता है, और इसलिए आप अटक जाते हैं।

सामान्य तौर पर, आप किसी भी महत्वपूर्ण कार्यों के एक withMVar कॉल में, यहां तक ​​कि आप हालांकि कर सकते हैं ऐसा नहीं करना चाहिए। और यदि आप इस तरह के किसी भी परिचालन करते हैं, तो आपको दोबारा सुनिश्चित करने की आवश्यकता है कि आप उन्हें समय-समय पर प्रभावी ढंग से संरक्षित करते हैं, जैसे कि आप सुनिश्चित हैं कि वे हमेशा एक या दूसरे तरीके से पूरा करते हैं।

+1

में 'popAllMVar''' देखें," ब्लॉक ... हमेशा के लिए "केवल इस अपवाद को ट्रिगर कर सकता है यदि जीएचसी रनटाइम साबित कर सकता है कि यह हमेशा के लिए अवरुद्ध है। क्या नेटवर्क इसका नेतृत्व कर सकता है? –

+0

@sclv यदि आप प्रसारण/sendTo/sendToExcept फ़ंक्शंस पर इंगित कर रहे हैं, तो नेटवर्क ऑपरेशंस को एमवीआर के बाहर ले जाना समस्या को ठीक नहीं करता है: डेडलॉक बनी रहती है। – Mattiemus

3

जो कोई भी इस पर ठोकर सकता है के लिए, कुछ अतिरिक्त जानकारी thread blocked indefinitely in an MVar operation वास्तव में है कि स्मार्ट नहीं है। ऐसा तब होता है जब एमवीआर के संदर्भ में प्रत्येक धागे उस स्थान पर पढ़ने (या लिखने) की कोशिश कर रहा है, मर गया है, या हमेशा के लिए अवरुद्ध एक और आदिम पर इंतजार कर रहा है।जैसे धागा 1 धागा 2 जो कोई मृत, यह भी MVAr a, पढ़ने का प्रयास या MVAr b जो केवल 1.

निम्नलिखित कोड खुशी से सूत्र में करने के लिए लिखा जा सकता है पढ़ने के लिए कोशिश कर रहा पर इंतजार कर MVAr a को पढ़ने के लिए कोशिश कर रहा है और हमेशा के लिए लटका हुआ है:

do 
    a <- newEmptyMVar 
    forkIO (readMVar a >>= putStrLn) 
    putMVar a $ last $ repeat 0 
संबंधित मुद्दे