2012-10-19 18 views
6

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

प्रदर्शित इस वर्ग है:

public static class ExplorationManager 
{ 
    public static int Counter = 0; 

    public static void ExplorerMaker(List<int[]> validPaths, List<string> myParents, string[,] myExplorationMap, List<int[]> myPositions) 
    { 
     foreach (var thread in validPaths.Select 
     (path => new Explorer(myParents, path, myExplorationMap, myPositions)). 
     Select(explorer => new Thread(explorer.Explore))) 
      { 
       thread.Name = "Thread of " + Counter + " generation"; 
       Counter++; 
       thread.Start(); 
    } 
} 

}

वहाँ इस चर "अधिक" धागा सुरक्षित बनाने के लिए एक तरीका है?

+2

पागलपन, डुप्लिकेट प्रदर्शित करना, अत्यधिक उच्च मूल्य_ - इस कोड से वास्तव में समझा नहीं जा सकता है। –

उत्तर

25

इस प्रकार की सुरक्षा बढ़ाने के लिए आपको कम से कम 2 समस्याएं हैं जिन्हें आपको संबोधित करने की आवश्यकता है।

पहला वाला Counterprivate बनाना है। इसके वर्तमान रूप में चर 100% सार्वजनिक है और इसे एप्लिकेशन में कोड के किसी भी हिस्से द्वारा उत्परिवर्तित किया जा सकता है। आज यह सुरक्षित हो सकता है लेकिन कल आपको गलती करने से बचाने में कुछ भी नहीं है। आप अभी भी कोड के अन्य हिस्सों संपत्ति को पढ़ने में सक्षम होना चाहते हैं तो एक्सेसर

private static int m_counter; 
public static int Counter { 
    get { return m_counter; } 
} 

का उपयोग दूसरी समस्या यह है कि ++ एक स्थान है कि धागे के बीच साझा किया जाता है पर एक सुरक्षित संचालन नहीं है।यह निम्न कोड

Counter = Counter + 1; 

कर जो वास्तविकता में है के लिए बाहर फैलता

  1. लोड काउंटर
  2. लोड 1
  3. जोड़ने
  4. दुकान काउंटर

एक धागा कर सकते हैं किसी भी समय किसी भी समय बाधा डालें। यदि चरण 1, 2 या 3 पर एक थ्रेड बाधित होता है और दूसरा धागा अनुक्रम को पूरी तरह से निष्पादित करता है तो आप स्टाल मान जोड़ना/संग्रहीत करना समाप्त कर देंगे। यही कारण है कि ++ असुरक्षित है। धागे के बीच साझा मूल्य बढ़ाने के लिए सुरक्षित तरीका Interlocked.Increment का उपयोग करना है। यह इस उद्देश्य के लिए बिल्कुल डिजाइन किया गया है

Interlocked.Increment(ref m_counter); 
+0

यदि यह काम नहीं करता है, तो समस्या मेरे कोड के साथ है? या यह हासिल करने के अन्य तरीके हैं? –

5

आपको अपने स्थिर चर के सभी पढ़ने/लिखने के आसपास lock का उपयोग करने की आवश्यकता है। कुछ की तरह: - यह एक ही स्थान की रक्षा के लिए है क्योंकि तब धागे कर पढ़ता है पर्याप्त नहीं है या लिखते हैं अभी भी जब एक परिवर्तन कर सकते हैं

public static readonly object CounterLock = new object(); 

... 
lock (CounterLock) 
{ 
    Counter++; 
} 
... 

बिंदु सभी पढ़ता/लिखता ताला द्वारा संरक्षित किया जाना चाहिए कि है कहीं और एक ताला प्रभाव में है।

एक ताला कोड के एक क्षेत्र की सुरक्षा करता है, एक चर नहीं, इसलिए आपको साझा किए गए चर का उपयोग करने के लिए हर जगह लॉक की आवश्यकता होती है।

ध्यान दें कि आप अपने Counter चर पर लॉक नहीं कर सकते हैं - आपको एक संदर्भ प्रकार का उदाहरण लॉक के रूप में चाहिए, न कि मूल्य प्रकार। यही कारण है कि मैंने लॉक प्रकार के रूप में object का उपयोग किया (दूसरा जवाब वही था)।

+0

मुझे यह नहीं पता था। मैंने सोचा कि 'रन()' विधि से कक्षा तक पहुंच की सुरक्षा, वास्तव में इसे संरक्षित करता है। धन्यवाद। –

+0

काउंटर लॉक 'readonly' –

+0

@ XaweryWiśniowiecki हां होना चाहिए, आप सही हैं। मैं जवाब अपडेट करूंगा। धन्यवाद। – xxbbcc

1

आप स्थैतिक चर शुरू करने के लिए स्थिर कन्स्ट्रक्टर के साथ प्रयास कर सकते हैं। locking ऑब्जेक्ट प्रदान करने के लिए यह सबसे अच्छा अभ्यास है, इसलिए आपके पास ताले की ग्रैन्युलरिटी पर अच्छा नियंत्रण है।

3

कुछ इस तरह चाल करना चाहिए:

public static class ExplorationManager 
{ 
    public static int Counter = 0; 
    private static object _lock = new object(); 

    public static void ExplorerMaker(List<int[]> validPaths, List<string> myParents, string[,] myExplorationMap, List<int[]> myPositions) 
    { 
     foreach (var thread in validPaths.Select 
     (path => new Explorer(myParents, path, myExplorationMap, myPositions)). 
     Select(explorer => new Thread(explorer.Explore))) 
      { 
       thread.Name = "Thread of " + Counter + " generation"; 
       lock(_lock) 
       { 
        Counter++; 
        thread.Start(); 
       } 
    } 
} 
17

Interlocked वर्ग का उपयोग करें:

Interlocked.Increment(ref Counter); 
1

Interlocked.Increment एक और धागा सुरक्षित विकल्प है। यदि आपको केवल काउंटर की आवश्यकता है तो इसका उपयोग करना बहुत आसान है।

var newCounter = Interlocked.Increment(ref Counter) 
thread.Name = "Thread of " + (newCounter-1) + " generation"; 
संबंधित मुद्दे