2012-05-06 37 views
7

मान लीजिए हमारे पास एक से अधिक थ्रेड सभी एक ही समारोह बुला:एकाधिक सूत्र एक ही समारोह बुला

def foo 
    # do stuff ... 
end 

100.times do |i| 
    Thread.new do 
    foo 
    end 
end 

दो या अधिक धागे foo के अंदर वर्तमान में कर रहे हैं, वे प्रत्येक शेयर foo भीतर ही स्थानीय चर?

यह मेरे दूसरे प्रश्न से संबंधित है। क्या थ्रेड में अलग-अलग स्टैक फ्रेम होते हैं, या क्या वे एक ही प्रक्रिया में स्टैक फ्रेम साझा करते हैं? विशेष रूप से, जब एकाधिक थ्रेड प्रत्येक foo और foo रिटर्न से पहले आते हैं, तो स्टैक पर foo की कई प्रतियां हैं, प्रत्येक के अपने स्थानीय चर के साथ, या स्टैक पर foo की केवल एक प्रति है?

उत्तर

4

हां, वे वही चर साझा करते हैं। यह थ्रेड का एक प्रमुख तत्व है और केवल पढ़ने के संदर्भ में ठीक है, लेकिन यदि वे किसी भी चर को लिखते हैं, तो आपको Mutex और synchronize धागे का उपयोग करने की आवश्यकता है, इसलिए केवल किसी भी समय किसी एक चर को बदल सकता है । कभी-कभी वे एक ऐसी विधि का आह्वान कर सकते हैं जो अप्रत्यक्ष रूप से डेटा को बदलता है, इसलिए आपको यह तय करने से पहले सिस्टम को पूरी तरह से जानना होगा कि आपको सिंक्रनाइज़ करने की आवश्यकता है या नहीं।

आपके दूसरे प्रश्न के लिए, यदि मैं समझता हूं कि आप क्या पूछ रहे हैं, तो उनके पास अलग-अलग स्टैक फ्रेम हैं, लेकिन वे अभी भी स्मृति में समान डेटा साझा कर रहे हैं।

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

zip = 42 

t = Thread.new do 
    zip += 1 
end 

t.join 

puts zip # => 43 

यहां शामिल होने से मुझे बचाता है, लेकिन स्पष्ट रूप से धागे में कोई बात नहीं है, अगर मैं वहां रहता हूं। अगर मैं निम्न करने के लिए थे यह खतरनाक होगा:

zip = 42 

t = Thread.new do 
    zip += 1 
end 

zip += 1 

puts zip # => either 43 or 44, who knows? 

है ऐसा इसलिए है क्योंकि आप मूल रूप से दो धागे दोनों एक ही समय में zip को संशोधित करने की कोशिश कर रहा है। जब आप उपरोक्त में नेटवर्क संसाधनों का उपयोग कर रहे हैं, या संख्या बढ़ाना आदि यह ध्यान देने योग्य हो जाता है।

निम्न उदाहरण में, हालांकि, स्थानीय चर zip एक पूरी तरह से नया दायरे के अंदर बनाई गई है, इसलिए दो धागे वास्तव में एक ही समय में एक ही चर के लिए लिख नहीं हैं:

def foo 
    zip = 42 
    zip += 1 # => 43, in both threads 
end 

Thread.new do 
    foo 
end 

foo 

वहाँ दो समांतर ढेर प्रबंधित किए जा रहे हैं, प्रत्येक foo विधि के अंदर अपने स्वयं के स्थानीय चर के साथ।

निम्नलिखित कोड है, तथापि, खतरनाक है:

@zip = 42 # somewhere else 

def foo 
    @zip += 1 
end 

Thread.new do 
    foo 
end 

foo 

puts @zip # => either 43 or 44, who knows? 

ऐसा इसलिए है क्योंकि उदाहरण चर @zipfoo समारोह के दायरे के बाहर से पहुंचा है, इसलिए दोनों धागे एक ही समय में यह पहुँच रहे हैं।

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

# somewhere else... 
@mutex = Mutex.new 
@zip = 42 

def foo 
    @mutex.synchronize do 
    @foo += 1 
    end 
end 

Thread.new do 
    foo 
end 

foo 

puts @zip # => 44, for sure! 

हैं जब निष्पादन के प्रवाह Mutex#synchronize लाइन तक पहुँच जाता है, यह म्युटेक्स लॉक करने के लिए कोशिश करता है। यदि सफल हो, तो यह ब्लॉक में प्रवेश करता है और निष्पादन जारी रखता है। एक बार ब्लॉक खत्म होने के बाद, म्यूटेक्स फिर से अनलॉक हो जाता है। यदि म्यूटेक्स पहले ही लॉक हो चुका है, तो धागा तब तक इंतजार कर रहा है जब तक कि यह फिर से मुक्त न हो जाए ... प्रभावी रूप से यह एक दरवाजे की तरह है कि केवल एक ही व्यक्ति एक समय में चल सकता है।

मुझे आशा है कि यह चीजों को साफ़ कर देगा।

+0

क्या आप केवल पढ़ने के लिए संदर्भ का उदाहरण दे सकते हैं? अगर foo एक स्थानीय चर बनाता है, तो उसे इसे कुछ असाइन करना होगा? –

+0

जो मैंने यहां पढ़ा है: "थ्रेड वैरिएबल" विषय के तहत http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_threads.html अलग-अलग लगता है। या मैं सो रहा हूँ। – alk

+1

आह, मैंने गलत समझा। यदि foo फ़ंक्शन स्थानीय चर बनाता है, तो यह ठीक है। यदि यह एक आवृत्ति चर बनाता है, हालांकि, जिसे अन्य धागे द्वारा एक्सेस किया जा सकता है, तो इसे म्यूटेक्स का उपयोग करना चाहिए। "केवल पढ़ने के लिए", मेरा मतलब यह है कि कोई आवृत्ति चर/वैश्विक चर संशोधित नहीं होते हैं। स्थानीय चर ठीक हैं ... वे वर्तमान धागे से संबंधित हैं। – d11wtq

0

विधि के अंदर परिभाषित स्थानीय चर साझा नहीं किए जाते हैं। लेकिन धागे के लिए थ्रेड ब्लॉक के दायरे में होने पर उसी ऑब्जेक्ट के इंस्टेंस वेरिएबल्स तक पहुंचना संभव है।

उदाहरण के लिए:

def foobar 
    puts "Foo is defined!" if defined?(foo)=='local-variable' 
    foo = 5 
end 

स्ट्रिंग डाल कभी नहीं होगा अगर एक से अधिक थ्रेड द्वारा कहा जाता है।

लेकिन निम्नलिखित एक म्युटेक्स की जरूरत है, सिंक्रनाइज़ किया क्योंकि दौड़ शर्तें लागू होती हैं:

foo = {bar:5} 
def foobar(value) 
    value[:bar]+=5 
end 
15.times{|i| Thread.new{foobar foo}} 

इस के बाद, foo [: बार] संभवतः 35 के एक मूल्य हो सकता है, foobar के हर कॉल के बाद, बदल जाता है एक हैश, फू के अंदर मूल्य।

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