2012-06-03 23 views
33

मैं एक कार्यकर्ता धागा है जो एक MVAr से बार-बार डेटा पढ़ता है और उस पर कुछ उपयोगी काम करता है एक धागा हत्या। थोड़ी देर के बाद, इस कार्यक्रम के बाकी है कि कार्यकर्ता धागा, जिसका अर्थ है कि यह एक खाली MVAr पर प्रतीक्षा करें और बहुत अकेला हो जाएगा के बारे में भूल जाता है। मेरा सवाल है:जब MVAr कचरा एकत्र किया जाता है

क्या एमवीआर कचरा इकट्ठा होगा यदि धागे अब इसे लिखते हैं, उदाहरण के लिए क्योंकि वे सभी इसके लिए प्रतीक्षा करते हैं? विल कचरा संग्रहण इंतजार कर रहे धागे को मारने? हैं न, मैं किसी भी तरह संकलक कि MVAr कचरा एकत्र किया जाना चाहिए और धागे को इंगित कर सकते हैं मारा जा?

संपादित करें: मुझे शायद अपने प्रश्न के उद्देश्य को स्पष्ट करना चाहिए। मैं deadlocks के खिलाफ सामान्य सुरक्षा की इच्छा नहीं है; इसके बजाय, मुझे क्या करना चाहते हैं एक मूल्य के जीवन के लिए कार्यकर्ता धागे के जीवन टाई (: मृत मान कचरा संग्रहण द्वारा दावा कर रहे हैं के रूप में में) है। दूसरे शब्दों में, कार्यकर्ता धागा एक संसाधन है कि मैं हाथ से नहीं मुक्त करना चाहते हैं, लेकिन कचरा एकत्र जब एक निश्चित मूल्य (MVAr या एक व्युत्पन्न) है।


यहाँ एक उदाहरण कार्यक्रम को दर्शाता है कि मेरे मन

import Control.Concurrent 
import Control.Concurrent.MVar 

main = do 
    something 
    -- the thread forked in something can be killed here 
    -- because the MVar used for communication is no longer in scope 
    etc 

something = do 
    v <- newEmptyMVar 
    forkIO $ forever $ work =<< takeMVar v 
    putMVar v "Haskell" 
    putMVar v "42" 

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

+1

यहां एमवीआर काम के कमजोर संदर्भ का उपयोग कर सकते हैं? –

+0

@ जॉन: वास्तव में, लेकिन क्या होगा अगर थ्रेड उस समय को सीमित करता है जब वह एमवीआर के लिए इंतजार कर रहा है और समय-समय पर जांच करता है कि कमजोर सूचक अभी भी जीवित है या नहीं? (कमजोर सूचक को शायद एक और मूल्य इंगित करना पड़ता है, जो एमवीआर के साथ-साथ गुंजाइश से बाहर निकलता है।) आदर्श रूप से, अवधि कचरा संग्रह की आवृत्ति द्वारा दी जानी चाहिए। –

+0

@HinrichApfelmus: मेरा पहला संपादन मूल रूप से इसे एक तरह से करता है। आपने एक और दृष्टिकोण सुझाया है जो शायद बेहतर है: अवरुद्ध धागे में एसिंक अपवाद बढ़ाने के लिए एक और धागा उत्पन्न करना, पढ़ने में बाधा डालना और इसे कमजोर सूचक से फिर से पढ़ने के लिए मजबूर करना। मैं आज बाद में कुछ कोड काम करने की कोशिश करूंगा। लेकिन फिर भी, यह भाषा के कुख्यात मुश्किल हिस्सों का उपयोग करके, बहुत से काम की तरह लगता है, जो कि डॉन तकनीक के साथ आसानी से सुलझाया जाता है। –

उत्तर

26

यह सिर्फ काम करेंगे: जब MVar केवल धागा है कि उस पर अवरुद्ध है द्वारा पहुंचा जा सकता है, तो धागा BlockedIndefinitelyOnMVar अपवाद है, जो सामान्य रूप से यह एक धागा ध्यान न दी के लिए चुपचाप (डिफ़ॉल्ट अपवाद संचालक मरने के लिए कारण होगा भेज दिया जाता है यह अपवाद)।

बीटीडब्ल्यू, थ्रेड मरने पर कुछ सफाई करने के लिए, आप forkFinally (जो मैं just added से Control.Concurrent) का उपयोग करना चाहूंगा।

+0

बढ़िया! मैं इसे लेता हूं कि मैं अभी भी थ्रेड में 'अवरुद्ध अंतहीनताऑनएमवर' अपवाद को पकड़ सकता हूं? –

+0

निश्चित रूप से, 'अवरुद्ध अंतहीनताऑनएमवीआर' सिर्फ एक साधारण अपवाद है। –

+2

क्या यह इस मामले में सच है कि एक एमवीआर कई धागे से पहुंच योग्य है, लेकिन वे सभी इस पर अवरुद्ध हैं? इसके अलावा, एक जीसी परिप्रेक्ष्य से, क्या इसका मतलब यह है कि जब एक एमएसआर पर एक टीएसओ अवरुद्ध हो जाता है, तो इसे लाइव सेट से निकाल दिया जाता है और केवल एमवीआर के माध्यम से पहुंच योग्य होता है? –

22

यदि आप भाग्यशाली हैं, तो आपको "BlockedIndefinitelyOnMVar" मिल जाएगा, यह दर्शाता है कि आप एक एमवीआर पर इंतजार कर रहे हैं कि कोई धागा कभी भी लिख नहीं पाएगा।

लेकिन, एड यांग उद्धृत करने के लिए,

GHC केवल जानता है कि एक धागा कचरा माना जा सकता है अगर वहाँ धागा करने के लिए कोई संदर्भ हैं। धागे का संदर्भ कौन रख रहा है? एमवीआर, थ्रेड के रूप में इस डेटा संरचना पर अवरुद्ध है और ने इसे अवरुद्ध करने वाली सूची में जोड़ा है। एमवीआर जीवित कौन रख रहा है? क्यों, हमारा बंद जिसमें एमवीआर लेने के लिए एक कॉल है। तो थ्रेड रहता है।

कुछ काम किए बिना (जो, वैसे, देखने के लिए काफी दिलचस्प होगा), अवरुद्ध इंडिफिनटाइमऑनएमवर आपके हास्केल प्रोग्राम डेडलॉक सुरक्षा देने के लिए एक स्पष्ट रूप से उपयोगी तंत्र नहीं है।

जीएचसी सामान्य रूप से समस्या को हल नहीं कर सकता है यह जानने के लिए कि आपका धागा प्रगति करेगा या नहीं।

एक बेहतर तरीका उन्हें Done संदेश भेजकर धागे को स्पष्ट रूप से समाप्त करना होगा। जैसे सिर्फ एक वैकल्पिक मूल्य है कि यह भी एक अंत के संदेश मूल्य भी शामिल है में अपना संदेश लिखें उठा:

import Control.Concurrent 
import Control.Concurrent.MVar 
import Control.Monad 
import Control.Exception 
import Prelude hiding (catch) 

main = do 
    something 

    threadDelay (10 * 10^6) 
    print "Still here" 

something = do 
    v <- newEmptyMVar 
    forkIO $ 
     finally 
      (let go = do x <- takeMVar v 
         case x of 
          Nothing -> return() 
          Just v -> print v >> go 
      in go) 
      (print "Done!") 

    putMVar v $ Just "Haskell" 
    putMVar v $ Just "42" 

    putMVar v Nothing 

और हम सही स्वच्छ उठो:

$ ./A 
"Haskell" 
"42" 
"Done!" 
"Still here" 
+1

आह, मैं देखता हूं, इसलिए मुझे हाथ से धागे को मारना है। (मैं इसके लिए एक अपवाद भी फेंक सकता हूं)। मुझे शायद यह स्पष्ट करना चाहिए कि मैं वास्तव में क्या करना चाहता था, हालांकि। अर्थात्, मैं थ्रेड के जीवन को मूल्य के जीवन में जोड़ना चाहता था, यानी थ्रेड को ऐसे संसाधन के रूप में मानें जो एमवीआर के कचरे के संग्रह पर मुक्त हो, जैसे 'रीडफाइल' के परिणाम के कचरे के संग्रह की तरह फ़ाइल को बंद करना चाहिए। –

11

मैं सरल कमजोर MVAr परीक्षण किया है और यह अंतिम रूप दिया और मारा गया।कोड है:

import Control.Monad 
import Control.Exception 
import Control.Concurrent 
import Control.Concurrent.MVar 
import System.Mem(performGC) 
import System.Mem.Weak 

dologger :: MVar String -> IO() 
dologger mv = do 
    tid <- myThreadId 
    weak <- mkWeakPtr mv (Just (putStrLn "X" >> killThread tid)) 
    logger weak 

logger :: Weak (MVar String) -> IO() 
logger weak = act where 
    act = do 
    v <- deRefWeak weak 
    case v of 
     Just mv -> do 
     a <- try (takeMVar mv) :: IO (Either SomeException String) 
     print a 
     either (\_ -> return()) (\_ -> act) a 
     Nothing -> return() 

play mv = act where 
    act = do 
    c <- getLine 
    if c=="quit" then return() 
     else putMVar mv c >> act 

doplay mv = do 
    forkIO (dologger mv) 
    play mv 

main = do 
    putStrLn "Enter a string to escape, or quit to exit" 
    mv <- newEmptyMVar 
    doplay mv 

    putStrLn "*" 
    performGC 
    putStrLn "*" 
    yield 
    putStrLn "*" 
    threadDelay (10^6) 
    putStrLn "*" 

कार्यक्रम के साथ सत्र था:

(chrisk)-(/tmp) 
(! 624)-> ghc -threaded -rtsopts --make weak2.hs 
[1 of 1] Compiling Main    (weak2.hs, weak2.o) 
Linking weak2 ... 

(chrisk)-(/tmp) 
(! 625)-> ./weak2 +RTS -N4 -RTS 
Enter a string to escape, or quit to exit 
This is a test 
Right "This is a test" 
Tab Tab 
Right "Tab\tTab" 
quit 
* 
* 
X 
* 
Left thread killed 
* 

तो takeMVar पर अवरुद्ध किया नहीं उम्मीदों के बावजूद जिंदा MVAr रखने GHC-7.4.1 पर।

+0

अच्छा! तो, आपका कोड स्पष्ट रूप से दर्शाता है कि फाइनलर चलाया जाता है जबकि थ्रेड अभी भी एमवीआर की प्रतीक्षा कर रहा है। ऐसा लगता है कि 'टेकएमवर' एमवीआर के आंतरिक प्रतिनिधित्व को इस बिंदु पर विघटित करेगा कि "बाहरी हल" कचरा एकत्र किया जा सकता है। 'डेटा आलसी ए = आलसी ए' का उपयोग करके और 'एमवर स्ट्रिंग' पर सीधे 'आलसी (एमवर स्ट्रिंग)' पर अंतिम रूप देने के द्वारा किसी भी डेटा संरचना के लिए शायद इसी तरह का प्रभाव प्राप्त किया जा सकता है। –

+0

हाँ, मैंने इसे भी समझ लिया। अंतर addMVarFinalizer और addFinalizer के बीच है। एमवीआर में डाली गई आखिरी वस्तु अप्रत्याशित हो सकती है, लेकिन मुझे लगता है कि इस उपयोग के लिए यह ठीक है। –

1

जबकि BlockedIndefinitelyOnMVar काम करना चाहिए, ForeignPointer finalizers का उपयोग करने पर भी विचार करें। उनमें से सामान्य भूमिका सी संरचनाओं को हटाना है जो अब हास्केल में उपलब्ध नहीं हैं। हालांकि, आप उन्हें किसी भी आईओ फाइनलाइज़र संलग्न कर सकते हैं।

+0

अगर मुझे सही याद है, तो आप उन्हें किसी भी आईओ क्रिया को संलग्न नहीं कर सकते हैं, इसे सी फाइनलाइज़र होना चाहिए। क्या यह अभी भी सच है? –

+0

"एक रैपर स्टब का उपयोग करके बनाए गए हास्केल फ़ंक्शन के पॉइंटर को सही प्रकार के FunPtr का उत्पादन करने के लिए घोषित किया गया।" [विदेशी.पीआरटी] (http://www.haskell.org/ghc/docs/6.12.2/html/libraries/base-4.2.0.1/Foreign-Ptr.html#t%3AFunPtr) – dmbarbour

+0

यह इतना आसान नहीं है। http://www.haskell.org/ghc/docs/latest/html/users_guide/ffi-ghc.html –

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