2009-08-17 15 views
16

मैं एक सी # एप में "बॉक्स किए गए" ऑब्जेक्ट को लॉक करने का प्रयास कर रहा हूं, क्या यह संभव नहीं है?सी # थ्रेडिंग - लॉक ऑब्जेक्ट

 Thread b1 = new Thread(new ThreadStart(t1.w)); 
     b1.Start(); 
     Thread b2 = new Thread(new ThreadStart(t1.w)); 
     b2.Start(); 

हालांकि भाग अवरोधित नहीं है:

class t 
    { 
     System.Object t_x = new object(); 

     public t(int p) 
     { 
      t_x = p; 

     } 

     public void w() 
     { 
      lock (t_x) 
      { 
       for (int i = 0; i < 4; i++) 
       { 

        { 
         t_x = ((int)t_x) + 1; 
         Console.WriteLine(t_x); 
         Thread.Sleep(1000); 
        } 
       } 
      } 
     } 
    } 

अन्य वर्ग में मैं 2 धागे शुरू कर सकते हैं। जब मैं एक मनमानी वस्तु को लॉक करता हूं (यानी ऑब्जेक्ट ए = नई ऑब्जेक्ट() के रूप में निर्मित और संशोधित नहीं किया जाता है तो यह अच्छी तरह से लॉक हो जाता है। मुक्केबाजी ऑपरेशन किसी भी तरह से मेरे ऑब्जेक्ट "depromotes" है ??

+2

आप एक ताला ब्लॉक के भीतर ताला वस्तु क्यों पुन: असाइन हैं? यह उद्देश्य को हरा देता है - चूंकि सिंक्रनाइज़ेशन का पूरा बिंदु एक "साझा" संसाधन के लिए एक-दूसरे को ट्रामल करने से अलग धागे से बचने के लिए है। – Gishu

+0

मुझे लगता है कि उत्तर स्वीकार किया गया है कि यह अच्छा नहीं है –

+0

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

उत्तर

16

आपको एक अलग लॉक ऑब्जेक्ट बनाने की आवश्यकता है। समस्या यह है कि आप लूप के अंदर t_x को फिर से असाइन करते हैं। मान लें कि थ्रेड बी 1 लॉक स्टेटमेंट में बी 2 से पहले लूप के अंदर आता है, बी 2 को लॉक स्टेटमेंट के अंदर अनुमति दी जाएगी क्योंकि उस समय तक, टी_एक्स एक नई ऑब्जेक्ट होगी जिस पर लॉक नहीं है।

+0

मुझे लगता है कि मॉनिटर यह –

+4

@Cedric करने का बेहतर तरीका है - ली के उत्तर को अधिक सावधानीपूर्वक पढ़ें। 'लॉक' कथन बिल्कुल 'मॉनिटर.इंटर' और 'मॉनीटर.एक्सिट' का उपयोग करने जैसा ही है। यह एक ही पैटर्न के लिए सिर्फ एक neater वाक्यविन्यास है। मुद्दा यह नहीं है कि 'लॉक' या 'मॉनिटर' का उपयोग करना है (वास्तव में एक विकल्प नहीं, क्योंकि वे वही हैं)। समस्या हमेशा लॉक के रूप में कार्य करने के लिए एक ही ऑब्जेक्ट को पास करना है, जो कि यदि आप किसी मान प्रकार का उपयोग करते हैं तो टूटा हुआ है क्योंकि इसे कभी भी एक्सेस करने के समय अलग-अलग बॉक्स किया जाता है। –

23

नहीं, आप ऐसा नहीं कर सकते - लॉक ब्लॉक निम्नलिखित के लिए आशुलिपि है:

try(Monitor.Enter(lockObject)) 
{ 
    //critical section 
} 
finally 
{ 
    Monitor.Exit(lockObject) 
} 

documentation for Monitor.Enter राज्यों, "मॉनिटर का प्रयोग करें वस्तुओं (अर्थात, संदर्भ प्रकार), नहीं मूल्य प्रकार लॉक करने के लिए जब आप एक मान प्रकार परिवर्तक को एंटर करने के लिए पास करते हैं, तो उसे ऑब्जेक्ट के रूप में बॉक्स किया जाता है। यदि आप एक ही वैरिएबल को फिर से एंटर करने के लिए पास करते हैं, तो इसे एक अलग ऑब्जेक्ट के रूप में बॉक्स किया जाता है, और थ्रेड "

+0

यह करने का अच्छा तरीका है। यह माइक्रोसॉफ्ट प्रमाणीकरण की पहली परीक्षा 70-536 में है। –

+7

यह सही उत्तर है - कोड स्निपेट की वजह से नहीं ('लॉक' कथन ठीक है) लेकिन क्योंकि यह मान और संदर्भ प्रकारों के बीच अंतर का उल्लेख करता है। जब भी इसे सार्वभौमिक 'ऑब्जेक्ट' बेस क्लास में परिवर्तित किया जाता है, तो एक वैल्यू टाइप फिर से बॉक्स किया जाता है, इसलिए यह विश्वसनीय रूप से लॉकिंग लक्ष्य के रूप में कार्य नहीं कर सकता है। तो यह स्वीकृत उत्तर से बेहतर है। –

2

को अवरुद्ध नहीं करता है लॉक

object lockObj = new object(); 
public void foo() 
{ 
    lock(lockObj) 
    { 
    //do stuff here 
    } 
} 
के लिए एक अतिरिक्त ऑब्जेक्ट का उपयोग करें
2

लॉक (t_x) कॉल एक अस्थायी वस्तु के रूप में एक पूर्णांक को कॉल करता है। लॉक करने के लिए प्रत्येक कॉल (t_x) एक नई वस्तु बनाता है और लॉकिंग बेकार है।

(लॉक एक वस्तु की उम्मीद है और पूर्णांक से एक नया अस्थायी वस्तु बनाता है)

बस एक अलग ताला वस्तु बनाने की तरह Femaref से ऊपर कहा।

0

तुम सच में चाहते हैं (? जरूरत है) वस्तु पर लॉक करने के लिए, आप आवरण का एक प्रकार का उपयोग कर सकते हैं:

public class ObjectWrapper 
{ 
    public Object Value { get;set; } 
} 
+0

जबकि मैं इसे इस तरह से करने की अनुशंसा नहीं करता हूं (केवल लॉक करने के लिए किसी अन्य 'ऑब्जेक्ट' का उपयोग करें), मैं डाउनवॉट्स को समझ नहीं पा रहा हूं, क्योंकि यह सही है। –

0

हैं:

public class IntWrapper 
{ 
    public int Value{get;set;} 
} 

या आप अधिक सार रहने की जरूरत है, तो आप यह जानना चाहते हैं कि डेटा लोड होने पर और यदि उपयोग पहले से इसका उपयोग करने का प्रयास करता है, तो आप ऐसा कुछ भी कर सकते हैं:

आपके जैसे बूलियन ध्वज का उल्लेख करें, लेकिन पहले लॉक करने के लिए एक अलग ऑब्जेक्ट का उपयोग करें क्रॉस-थ्रेड रेस स्थितियों को रोकने के लिए इसे एक्सेस करना।

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

उदाहरण:

public class MyClass 
{ 
    private bool dataIsReady = false; 
    private object locker = new object(); 
    BackgroundWorker worker; 

    public void Begin() 
    { 
     worker = new BackgroundWorker(); 
     worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted); 
    } 

    public void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     lock (locker) 
     { 
      dataIsReady = true; 
     } 
    } 

    public void UseTriesToUseData() 
    { 
     lock (locker) 
     { 
      if (dataIsReady) 
      { 
       DoStuff(); 
      } 
      else 
      { 
       this.worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(DoStuffCaller); 
      } 
     } 
    } 

    private void DoStuff() 
    { 
     // Do stuff with data. 
    } 

    private void DoStuffCaller(object sender, RunWorkerCompletedEventArgs e) 
    { 
     this.DoStuff(); 
    } 
} 
संबंधित मुद्दे