क्या एक विधि धागा सुरक्षित बनाता है? नियम क्या हैं?


156

क्या एक विधि धागा-सुरक्षित बनाने के लिए समग्र नियम / दिशानिर्देश हैं? मैं समझता हूं कि संभवत: एक लाख एक-बंद स्थितियां हैं, लेकिन सामान्य रूप से इसका क्या? क्या यह सरल है?

  1. यदि कोई विधि केवल स्थानीय चर को एक्सेस करती है, तो यह थ्रेड सुरक्षित है।

क्या यही है? क्या यह स्थैतिक तरीकों के लिए भी लागू होता है?

@Cybis द्वारा प्रदान किया गया एक उत्तर था:

स्थानीय चर को थ्रेड के बीच साझा नहीं किया जा सकता क्योंकि प्रत्येक थ्रेड का अपना स्टैक होता है।

क्या यह स्थैतिक तरीकों के लिए भी है?

यदि किसी विधि को संदर्भ ऑब्जेक्ट पास किया जाता है, तो क्या वह थ्रेड सुरक्षा को तोड़ता है? मैंने कुछ शोध किए हैं, और कुछ मामलों के बारे में बहुत कुछ है, लेकिन मैं उम्मीद कर रहा था कि परिभाषित करने में सक्षम हो सकता है, बस कुछ नियमों का उपयोग करके, यह सुनिश्चित करने के लिए दिशानिर्देशों का पालन करना है कि कोई विधि थ्रेड सुरक्षित है।

तो, मुझे लगता है कि मेरा अंतिम प्रश्न है: "क्या नियमों की एक छोटी सूची है जो एक थ्रेड-सुरक्षित पद्धति को परिभाषित करती है? यदि हां, तो वे क्या हैं?"

EDIT यहां
बहुत सारे अच्छे बिंदु बनाए गए हैं। मुझे लगता है कि इस सवाल का असली जवाब है: "धागा सुरक्षा सुनिश्चित करने के लिए कोई सरल नियम नहीं हैं।" ठंडा। ठीक। लेकिन सामान्य तौर पर मुझे लगता है कि स्वीकृत उत्तर एक अच्छा, संक्षिप्त सारांश प्रदान करता है। हमेशा अपवाद होते हैं। ऐसा ही होगा। में इसके साथ जी सकता हूँ।


59
तुम एक चर के बिना अन्य धागे द्वारा भी उपयोग कर रहे हैं कि चर का उपयोग नहीं होगा।
हंस पैसेंट

4
हैनट पैंथर हठ में बदल गया!
मार्टिन जेम्स

3
इसके अलावा .. 'आप उन वैरिएबल्स तक नहीं पहुंच सकते जो लॉकेट के बिना अन्य थ्रेड्स द्वारा भी एक्सेस किए जाते हैं' - यह इस बात को स्पष्ट करता है कि यदि पढ़ा गया वैल्यू ऑसिअसली नवीनतम नहीं है या वास्तव में बिलकुल गलत है।
मार्टिन जेम्स

यहाँ एरिक द्वारा एक अच्छा ब्लॉग आपको एक चक्कर में ले जाने के लिए है।
RBT

जवाबों:


139

यदि कोई विधि (उदाहरण या स्थैतिक) केवल संदर्भ चर उस पद्धति के भीतर है, तो यह थ्रेड सुरक्षित है क्योंकि प्रत्येक थ्रेड का अपना स्टैक है:

इस उदाहरण में, कई थ्रेड्स ThreadSafeMethodबिना किसी समस्या के समवर्ती कॉल कर सकते हैं ।

public class Thing
{
    public int ThreadSafeMethod(string parameter1)
    {
        int number; // each thread will have its own variable for number.
        number = parameter1.Length;
        return number;
    }
}

यह भी सच है अगर विधि अन्य वर्ग विधि को कॉल करती है जो केवल स्थानीय रूप से स्कोप किए गए चर का संदर्भ देती है:

public class Thing
{
    public int ThreadSafeMethod(string parameter1)
    {
        int number;
        number = this.GetLength(parameter1);
        return number;
    }

    private int GetLength(string value)
    {
        int length = value.Length;
        return length;
    }
}

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

public class Thing
{
    private string someValue; // all threads will read and write to this same field value

    public int NonThreadSafeMethod(string parameter1)
    {
        this.someValue = parameter1;

        int number;

        // Since access to someValue is not synchronised by the class, a separate thread
        // could have changed its value between this thread setting its value at the start 
        // of the method and this line reading its value.
        number = this.someValue.Length;
        return number;
    }
}

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

उचित संगामिति सुनिश्चित करने के लिए आपको लॉकिंग का उपयोग करने की आवश्यकता है।

अधिक जानकारी के लिए लॉक स्टेटमेंट C # संदर्भ और ReadWriterLockSlim देखें

ताला ज्यादातर समय कार्यक्षमता प्रदान करने के लिए उपयोगी होता है,
ReadWriterLockSlimयदि आपको कई पाठकों और एकल लेखकों की आवश्यकता होती है।


15
तीसरे उदाहरण में private string someValue;ऐसा नहीं है staticकि प्रत्येक उदाहरण को उस चर की एक अलग प्रति मिलेगी। तो क्या आप यह समझा सकते हैं कि यह धागा सुरक्षित कैसे नहीं है?
भारद्वाज

29
@ भारद्वाज अगर Thingकई धागों द्वारा अभिगम किए गए वर्ग का एक उदाहरण है
ट्रेवर पिली

111

यदि कोई विधि केवल स्थानीय चर को एक्सेस करती है, तो यह थ्रेड सुरक्षित है। क्या यही है?

बिलकुल नहीं। आप एक एकल थ्रेड से केवल एक ही स्थानीय चर के साथ एक प्रोग्राम लिख सकते हैं जो कि थ्रेडसेफ़ नहीं है:

https://stackoverflow.com/a/8883117/88656

क्या यह स्थैतिक तरीकों के लिए भी लागू होता है?

बिलकुल नहीं।

@Cybis द्वारा प्रदान किया गया एक उत्तर था, "थ्रेड्स के बीच स्थानीय चर साझा नहीं किए जा सकते क्योंकि प्रत्येक थ्रेड का अपना स्टैक होता है।"

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

क्या यह स्थैतिक तरीकों के लिए भी है?

बिलकुल नहीं।

यदि किसी विधि को संदर्भ ऑब्जेक्ट पास किया जाता है, तो क्या वह थ्रेड सुरक्षा को तोड़ता है?

शायद।

मैंने कुछ शोध किए हैं, और कुछ मामलों के बारे में बहुत कुछ है, लेकिन मैं उम्मीद कर रहा था कि कुछ नियमों का उपयोग करके परिभाषित किया जा सकता है, यह सुनिश्चित करने के लिए दिशानिर्देशों का पालन करना है कि एक विधि थ्रेड सुरक्षित है।

आपको निराशा के साथ जीना सीखना होगा। यह बहुत कठिन विषय है।

तो, मुझे लगता है कि मेरा अंतिम प्रश्न यह है: "क्या नियमों की एक छोटी सूची है जो एक थ्रेड-सुरक्षित पद्धति को परिभाषित करती है?

नहीं। जैसा कि आपने पहले मेरे उदाहरण से देखा कि एक खाली विधि गैर-थ्रेड-सुरक्षित हो सकती है । आप के रूप में अच्छी तरह से पूछ सकते हैं "नियमों की एक छोटी सूची है जो सुनिश्चित करता है कि एक विधि सही है "। नहीं वहाँ नहीं है। थ्रेड सुरक्षा एक अत्यंत जटिल प्रकार की शुद्धता से अधिक कुछ नहीं है।

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

फिर से, मेरे उदाहरण को देखें: प्रत्येक विधि तुच्छ है । यह वह तरीका है जो विधियां एक "वैश्विक" स्तर पर एक दूसरे के साथ बातचीत करती हैं जो कार्यक्रम को गतिरोध बनाती हैं। आप प्रत्येक विधि को नहीं देख सकते हैं और इसे "सुरक्षित" के रूप में देख सकते हैं और फिर उम्मीद कर सकते हैं कि पूरा कार्यक्रम सुरक्षित है, इससे अधिक कोई भी आप यह निष्कर्ष निकाल सकते हैं कि आपका घर 100% गैर-खोखली ईंटों से बना है जो घर भी है गैर खोखला। एक घर का खोखलापन पूरी चीज की एक वैश्विक संपत्ति है, न कि इसके भागों के गुणों का एक समूह।


14
मुख्य कथन: थ्रेड सुरक्षा एक वैश्विक, एक कार्यक्रम की स्थानीय संपत्ति नहीं है।
ग्रेग डी

5
@ थोबॉर्न: class C { public static Func<int> getter; public static Action<int> setter; public static void M() { int x = 0; getter = ()=>x; setter = y=>{x=y;};} } कॉल एम (), फिर सी। और सी। को दो अलग-अलग थ्रेड पर कॉल करें। स्थानीय चर को अब दो अलग-अलग धागों पर लिखा और पढ़ा जा सकता है, भले ही वह स्थानीय हो। दोबारा: स्थानीय चर की परिभाषित विशेषता यह है कि यह स्थानीय है , न कि यह धागे के ढेर पर है
एरिक लिपर्ट

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

7
@EricLippert: कई वर्गों के लिए MSDN प्रलेखन घोषित करता है कि 'सार्वजनिक स्थैतिक (विजुअल बेसिक में साझा) इस प्रकार के सदस्य थ्रेड सुरक्षित हैं। किसी भी उदाहरण के सदस्यों को धागा सुरक्षित होने की गारंटी नहीं है। ' या कभी-कभी 'यह प्रकार थ्रेड सुरक्षित है।' (उदाहरण स्ट्रिंग), जब थ्रेड-सेफ्टी वैश्विक चिंता का विषय है तो ये गारंटी कैसे दी जा सकती है?
माइक जोबरे

3
@ मायिकज़: अच्छा सवाल। या तो वे विधियां किसी भी राज्य को उत्परिवर्तित नहीं करती हैं, या जब वे करते हैं, तो वे ताले के बिना सुरक्षित रूप से राज्य को बदलते हैं, या, यदि वे ताले का उपयोग करते हैं, तो वे इस तरह से करते हैं कि गारंटी देता है कि वैश्विक "लॉक ऑर्डर" का उल्लंघन नहीं किया गया है। स्ट्रिंग्स अपरिवर्तनीय डेटा संरचनाएं हैं जिनके तरीके कुछ भी नहीं बदलते हैं, इसलिए स्ट्रिंग को आसानी से सुरक्षित बनाया जा सकता है।
एरिक लिपर्ट

11

कोई कठिन और तेज नियम नहीं है।

.NET में कोड थ्रेड को सुरक्षित बनाने के लिए यहां कुछ नियम दिए गए हैं और ये अच्छे नियम क्यों नहीं हैं:

  1. फ़ंक्शन और सभी फ़ंक्शन जो इसे कहते हैं, शुद्ध होना चाहिए (कोई साइड इफेक्ट नहीं) और स्थानीय चर का उपयोग करें। यद्यपि यह आपके कोड को थ्रेड-सुरक्षित बना देगा, लेकिन बहुत कम दिलचस्प चीजें हैं जो आप .NET में इस प्रतिबंध के साथ कर सकते हैं।
  2. प्रत्येक फ़ंक्शन जो एक सामान्य ऑब्जेक्ट पर संचालित होता है, उसे lockएक सामान्य चीज़ पर होना चाहिए । सभी ताले एक ही क्रम में किए जाने चाहिए। इससे कोड थ्रेड सुरक्षित हो जाएगा, लेकिन यह अविश्वसनीय रूप से धीमा होगा, और आप कई थ्रेड का उपयोग नहीं कर सकते हैं।
  3. ...

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


10
ताले को धीमा नहीं होना चाहिए। ताले अविश्वसनीय रूप से तेज़ हैं; निर्विरोध ताला दस से सौ नैनोसेकंड के परिमाण के क्रम में है । निहित ताले बेशक धीमी गति से होते हैं; यदि आपको धीमा कर दिया जाता है क्योंकि आप ताले से लड़ रहे हैं तो विवाद को दूर करने के लिए प्रोग्राम को खोजें
एरिक लिपर्ट

2
मुझे लगता है कि मैं # 2 को पर्याप्त स्पष्ट करने में विफल रहा। मैं यह कहना चाह रहा था कि थ्रेड्स को सुरक्षित बनाने का एक तरीका है: किसी भी सामान्य वस्तुओं की प्रत्येक पहुंच के चारों ओर ताले लगाना। और यह मानते हुए कि कई धागे हैं, यह विवाद पैदा करेगा, और ताले पूरी चीज को धीमा कर देंगे। तालों को जोड़ते समय, कोई केवल नेत्रहीन रूप से ताले नहीं जोड़ सकता है, उन्हें बहुत अच्छे रणनीतिक स्थानों पर रखा जाना चाहिए।
इयरलैमलेस

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.