2012-08-25 22 views
5

http://www.codeproject.com/Articles/28785/Thread-synchronization-Wait-and-Pulse-demystifiedMonitor.Pulse और प्रतीक्षा करें - अनपेक्षित व्यवहार

कतार:

तैयार कतार है कि एक विशेष लॉक के लिए इंतजार कर रहे हैं धागे का संग्रह है। मॉनिटर। वैट विधियां एक और कतार पेश करती हैं: प्रतीक्षा कतार। लॉक प्राप्त करने के इंतजार से पल्स के लिए प्रतीक्षा करने के लिए यह आवश्यक है । तैयार कतार की तरह, प्रतीक्षा कतार फीफो है।

अनुशंसित पैटर्न:

इन कतारों अनपेक्षित व्यवहार हो सकता है। जब एक पल्स होता है, प्रतीक्षा कतार का प्रमुख जारी किया जाता है और इसे कतार में जोड़ा जाता है। हालांकि, अगर तैयार कतार में अन्य धागे हैं, तो वे जारी किए गए थ्रेड से पहले लॉक प्राप्त करेंगे। यह समस्या है, क्योंकि लॉक प्राप्त करने वाला थ्रेड राज्य को बदल सकता है कि स्पंदित धागा निर्भर करता है। समाधान ताला बयान

* क्यू = कतार अंदर थोड़ी देर हालत का प्रयोग है।

इसके द्वारा, मैं समझता हूं कि जब मैं Pulse पर कॉल करता हूं, तो यह समाप्त होने से पहले 2 चीजें करता है। सबसे पहले, यह प्रतीक्षा क्यू से तैयार क्यू तक एक थ्रेड हटा देता है। दूसरा, यह तैयार क्यू में लॉक प्राप्त करने में एक थ्रेड (बिना थ्रेड कौन जानता है) देता है; यह परवाह नहीं करता कि कौन लॉक प्राप्त करता है (थ्रेड जो प्रतीक्षा प्रश्न से आया था या किसी थ्रेड के लिए तैयार क्यू में था)।

अगर मैं उस के बारे में सही हूँ तो क्यों रहा है इस समस्या को ठीक करने के लिए मदद एक whileMonitor.Wait से पहले (समस्या - नाड़ी समाप्त हो जाती है, भले ही धागा है कि इंतजार कर क्यू से आया ताला हासिल नहीं किया है)?

मुझे बताएं कि क्या मैं Monitor.Pulse के उद्देश्य के बारे में सही हूं।

बीPulse आप हर बार जब आप का उत्पादन -

class Program 
{ 
    static Queue<int> queue = new Queue<int>(); 
    static object someMonitor = new object(); 

    static void Main(string[] args) 
    { 
     Thread Thread1 = new Thread(WorkAlltheTime); 
     Thread1.Name = "Thread1"; 
     Thread Thread2 = new Thread(WorkAlltheTime); 
     Thread2.Name = "Thread2"; 
     Thread Thread3 = new Thread(WorkOnce); 
     Thread3.Name = "Thread3"; 
     Thread1.Start(); 
     Thread2.Start(); 
     Thread.Sleep(1000); 
     Thread3.Start(); 
     Console.ReadLine(); 
    } 

    static void WorkAlltheTime() 
    { 
     Console.WriteLine("Came in to Ready Q: " + Thread.CurrentThread.Name); 
     lock (someMonitor) 
     { 
      Console.WriteLine("Came out from Ready Q: " + Thread.CurrentThread.Name); 
      // Broken! 
      while (queue.Count == 0) 
      { 
       Console.WriteLine("Came in to Waiting Q: " + Thread.CurrentThread.Name); 
       Monitor.Wait(someMonitor); 
       Console.WriteLine("Came out from Waiting Q: " + Thread.CurrentThread.Name); 
      } 
      queue.Dequeue(); 
      Console.WriteLine("Thread: "+Thread.CurrentThread.Name+" Pulled Out"); 
     } 
    } 

    static void WorkOnce() 
    { 
     lock (someMonitor) 
     { 
      queue.Enqueue(1); 
      Monitor.Pulse(someMonitor); 
     } 
    } 
} 

उत्तर

9

कल्पना कीजिए कि आप एक निर्माता/उपभोक्ता कतार लिखने के लिए कोशिश कर रहे हैं: क्यों मैं एक whileMonitor.Wait से पहले

नीचे जवाब से भरा कोड डाल करने की आवश्यकता है एक वस्तु, और एक उपभोक्ता को तब तक इंतजार करना पड़ता है जब तक उपभोग करने के लिए कोई वस्तु न हो। आप इस तरह कोड लिखने चाहते हैं:

Foo item; 
lock(someMonitor) 
{ 
    while (queue.Count == 0) 
    { 
     Monitor.Wait(someMonitor); 
    } 
    item = queue.Dequeue(); 
} 
// Use the item 

मान लीजिए आप जबकि पाश नहीं था, और इसके बजाय लिखा है:

Foo item; 
lock(someMonitor) 
{ 
    // Broken! 
    if (queue.Count == 0) 
    { 
     Monitor.Wait(someMonitor); 
    } 
    item = queue.Dequeue(); 
} 
// Use the item 

अब मान लीजिए कि आप एक थ्रेड पहले से ही इंतजार कर रहे है, और फिर एक और लॉक स्टेटमेंट से ठीक पहले थ्रेड ... फिर एक निर्माता मॉनिटर को दाल करता है (और निश्चित रूप से कतार में एक आइटम जोड़ता है)।

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

जबकि लूप के साथ, आप अगले आइटम का उत्पादन होने तक फिर से प्रतीक्षा करेंगे, जो आप वास्तव में चाहते हैं।

+0

धन्यवाद, मैंने आपके उदाहरण का पूरा कोड लिखा है और आपकी व्याख्या के साथ मैंने इसे 90 बार परीक्षण किया और अब मैं पूरी तरह से समझता हूं। धन्यवाद एजियन! –