2010-07-23 18 views
17

प्रत्येक के धागे का अपना ढेर होता है, लेकिन वे एक सामान्य ढेर साझा करते हैं।धागे ढेर की जगह क्यों साझा करते हैं?

स्थानीय/विधि चर के लिए स्टैक सभी के लिए यह स्पष्ट है & ढेर उदाहरण/कक्षा चर के लिए है।

धागे के बीच ढेर साझा करने का क्या फायदा है।

कई धागे एक साथ चल रहे हैं, इसलिए स्मृति साझा करने से समवर्ती संशोधन, आपसी बहिष्करण आदि ओवरहेड जैसे मुद्दों का कारण बन सकता है। ढेर में धागे द्वारा कौन सी सामग्री साझा की जाती है।

ऐसा क्यों है? प्रत्येक थ्रेड के पास अपने ही ढेर का मालिक क्यों नहीं है? क्या कोई इस के वास्तविक दुनिया का उदाहरण प्रदान कर सकता है, धागे द्वारा साझा की गई स्मृति का उपयोग कैसे किया जाता है?

+2

यह प्रश्न वास्तव में कुछ स्पष्टीकरण का उपयोग कर सकता है। उदाहरण के लिए, "व्यावहारिक विचार" और "वास्तविक समय उदाहरण" का क्या अर्थ है? साथ ही, यह होमवर्क जैसा लगता है ... कृपया इसे टैग करें जैसे कि यह है। – jdmichal

+1

मैंने इसे फिर से लिखा है, लेकिन यदि यह प्रश्न का इरादा नहीं है, तो इसे वापस रोल करें या संशोधित करें। –

+0

नहीं, यह हर किसी के लिए स्पष्ट नहीं है कि ढेर उदाहरण/वर्ग चर के लिए है। ढेर पर संग्रहीत करने के लिए अन्य उपयोगी चर हैं, और कई भाषाओं में उदाहरण/कक्षा चर ढेर पर होते हैं। – Puppy

उत्तर

34

जब आप एक थ्रेड से दूसरे डेटा को पास करना चाहते हैं तो आप क्या करते हैं? (यदि आप कभी नहीं किया है कि आप अलग कार्यक्रमों लेखन होता जा, एक बहु लड़ी कार्यक्रम नहीं।) दो प्रमुख दृष्टिकोण हैं:

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

    प्रति थ्रेड एक ढेर, साथ ही एक साझा ढेर होना संभव है। इसके लिए प्रोग्रामर को यह तय करने की आवश्यकता होती है कि कौन सा डेटा कहां रखा जाए, और यह अक्सर मौजूदा प्रोग्रामिंग भाषाओं के साथ अच्छी तरह से जाल नहीं करता है।

  • दोहरी दृष्टिकोण संदेश पास हो रहा है: प्रत्येक थ्रेड की अपनी डेटा स्थान होती है; जब कोई धागा किसी अन्य थ्रेड के साथ संवाद करना चाहता है तो उसे अन्य धागे को स्पष्ट रूप से एक संदेश भेजने की आवश्यकता होती है, ताकि प्राप्तकर्ता के ढेर से प्राप्तकर्ता के ढेर तक डेटा कॉपी किया जा सके। इस सेटिंग में कई समुदाय थ्रेड प्रक्रियाओं को कॉल करना पसंद करते हैं। यही कारण है कि आप सुरक्षा देता है: के बाद से एक धागा एक लहर पर कुछ अन्य धागे की स्मृति ओवरराइट नहीं कर सकते, कीड़े का एक बहुत परहेज कर रहे हैं। एक अन्य लाभ वितरण: आप अपने थ्रेड को अलग-अलग मशीनों पर अपने प्रोग्राम में एक लाइन को बदलने के बिना चला सकते हैं। आप अधिकांश भाषाओं के लिए संदेश पास करने वाले पुस्तकालयों को पा सकते हैं लेकिन एकीकरण कम अच्छा होता है। Erlang और JoCaml में संदेश भेजने के लिए अच्छी भाषाएं हैं।

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

+1

उत्कृष्ट जवाब। वास्तव में, कुछ पुराने ऑपरेटिंग सिस्टम ने सिस्टम में सभी कार्यक्रमों को अनिवार्य रूप से एक बड़ी प्रणाली प्रक्रिया में धागे के रूप में माना (मुझे लगता है कि सिस्टम/360 ने ऐसा किया है?)। साझा स्मृति और संदेश पासिंग के बीच दार्शनिक अंतर आज भी विंडोज और यूनिक्स के बीच डिजाइन अंतर के दिल में है। –

+0

@ डैनियल: कई एम्बेडेड सिस्टम अभी भी करते हैं, क्योंकि जब आप अपनी मेमोरी को केबी में गिनती करते हैं तो प्रोसेस अलगाव महंगी होती है, और इसके लिए हार्डवेयर समर्थन (आमतौर पर एमएमयू के माध्यम से) की आवश्यकता होती है। मुझे समझ में नहीं आता कि विंडोज और यूनिक्स समेकन के इलाज में भिन्न हैं, क्या आप थोड़ा विस्तार कर सकते हैं? – Gilles

+1

मेरा मतलब यह है कि विंडोज प्लेटफ़ॉर्म थ्रेडिंग के लिए ओएस-स्तरीय समर्थन के साथ साझा मेमोरी समाधान का समर्थन करता है। दूसरी तरफ, यूनिक्स ने परंपरागत रूप से साझा मेमोरी समाधानों पर पाइप और सॉकेट के माध्यम से संचार को प्राथमिकता दी है। यह किसी भी तरह से कठिन और तेज़ भेद नहीं है, क्योंकि दोनों समाधान दोनों प्लेटफार्मों पर उपलब्ध हैं, लेकिन प्रत्येक के पास इसका "पसंदीदा" तरीका है, और इससे मेरी टिप्पणी में वर्णित "दार्शनिक अंतर" होता है। –

3

प्रक्रियाएं नहीं - सामान्य रूप से - ढेर स्थान साझा करें। एपीआई को अनुमति देने के लिए एपीआई है, लेकिन डिफ़ॉल्ट यह है कि प्रक्रियाएं अलग हैं

थ्रेड्स शेयर ढेर स्पेस।

यह "व्यावहारिक विचार" है - स्मृति का उपयोग करने के दो तरीके - साझा और साझा नहीं किए गए हैं।

+0

प्रक्रियाएं हीप स्पेस साझा कर सकती हैं - साझा मेमोरी एपीआई इसे प्रदान करते हैं। ओह, और विंडोज 3.1 -> विंडोज़ ने शेयर ढेर :) – gbjbaanb

+1

को पूरा करने के लिए विशेष एपीआई की आवश्यकता है - डिफ़ॉल्ट नहीं। –

+0

लिनक्स पर आप 'क्लोन()' का उपयोग करके जो भी चाहें साझा कर सकते हैं। –

2

कई भाषाओं/रनटाइम्स में स्टैक (अन्य के बीच) कार्य/विधि पैरामीटर और चर रखने के लिए उपयोग किया जाता है। अगर धागे ने एक ढेर साझा किया, तो चीजें वास्तव में गन्दा हो जाएंगी।

void MyFunc(int a) // Stored on the stack 
{ 
    int b; // Stored on the stack 
} 

जब 'MyFunc' के लिए कॉल किया जाता है, खड़ी पॉप जाता है और ए और बी ढेर पर नहीं रह गया है। चूंकि धागे स्टैक्स साझा नहीं करते हैं, इसलिए चर और ए के लिए कोई थ्रेडिंग समस्या नहीं है।

स्टैक की प्रकृति (धक्का/पॉपिंग) की वजह से यह वास्तव में 'दीर्घकालिक' स्थिति या फ़ंक्शन कॉल में साझा राज्य को रखने के लिए उपयुक्त नहीं है। इस तरह:

int globalValue; // stored on the heap 

void Foo() 
{ 
    int b = globalValue; // Gets the current value of globalValue 

    globalValue = 10; 
} 

void Bar() // Stored on the stack 
{ 
    int b = globalValue; // Gets the current value of globalValue 

    globalValue = 20; 
} 


void main() 
{ 
    globalValue = 0; 
    Foo(); 
    // globalValue is now 10 
    Bar(); 
    // globalValue is now 20 
} 
0

ऐसा इसलिए है क्योंकि धागे का विचार "सब कुछ साझा करें" है। बेशक, ऐसी कुछ चीजें हैं जिन्हें आप साझा नहीं कर सकते हैं, प्रोसेसर संदर्भ और ढेर की तरह, लेकिन बाकी सब कुछ साझा किया जाता है।

1

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

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

+0

पैडेंटिक होने के लिए, कई मेमोरी मैनेजर _do वास्तव में विभिन्न क्षेत्रों (एरिना) से स्मृति आवंटित करते हैं, लेकिन वे प्रदर्शन को बेहतर बनाने के लिए ऐसा करते हैं। बेशक, परिणामी स्मृति अभी भी साझा की गई है। – ninjalj

11

क्योंकि अन्यथा वे प्रक्रियाओं होगा। स्मृति साझा करने के लिए धागे का पूरा विचार है।

1

समस्या यह है कि स्थानीय ढेर होने के लिए बहुत कम मूल्य के लिए अत्यधिक जटिलता ला देता है।

वहाँ एक छोटा सा प्रदर्शन लाभ है और यह अच्छी तरह से TLAB द्वारा नियंत्रित किया जाता (थ्रेड स्थानीय आवंटन बफर) जो आप पारदर्शी रूप से लाभ के सबसे देता है।

1
एक बहु लड़ी आवेदन प्रत्येक थ्रेड अपने स्वयं के ढेर होगा, लेकिन एक ही ढेर का हिस्सा होगा

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

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