2015-03-03 8 views
5

मैं सी # में थ्रेडिंग के साथ प्रयोग कर रहा हूं, और मैंने परिणामस्वरूप निम्न श्रेणी बनाई है। मैंने दौड़ की स्थिति के किसी भी मामले से बचने की कोशिश की है, फिर भी उपयोग पर एक डेडलॉक होता है।ऑब्जेक्ट पूल क्लास में डेडलॉक

कक्षा दो अलग-अलग ताले, सीधी चाल के लिए एक स्पिनलॉक का उपयोग करती है, और अतिरिक्त रूप से Monitor लॉक करने के लिए लॉक करने के लिए कोई ऑब्जेक्ट तैयार नहीं होता है। मैंने मूल रूप से EventWaitHandle का उपयोग किया, लेकिन पाया कि WaitOne/Set प्राथमिकता के कारण दौड़ की स्थिति अनिवार्य थी।

ध्यान दें कि Monitor.PulseMonitor.Wait से पहले नहीं हो सकता था, तो डेडलॉक का कारण क्या हो सकता है? इस मामले में जहां 5 धागे TestPool कक्षा 4 की क्षमता वाले वर्ग का उपयोग करते हैं, तो डेडलॉक हमेशा अनियमित पल पर SpinLock पर होता है।

internal class TestPool<T> where T : class 
{ 
    private int capacity; 
    private int unitPos; 
    private int waitUnitPos; 
    private int waitCount; 
    private int lockState; 
    private object lockObj; 
    private T[] units; 
    private Func<T> unitFactory; 

    public TestPool(int capacity, Func<T> unitFactory) 
    { 
     this.lockObj = new object(); 
     this.unitFactory = unitFactory; 

     Init(capacity); 
    } 

    public T Fetch() 
    { 
     T unit; 

     Lock(); 
     unit = (unitPos != capacity) ? units[unitPos++] : Wait(); 
     Unlock(); 

     return unit; 
    } 

    public void Store(T unit) 
    { 
     Lock(); 

     if (waitCount == 0) 
     { 
      units[--unitPos] = unit; 
     } 
     else 
     { 
      Pulse(unit); 
     } 

     Unlock(); 
    } 

    private T Wait() 
    { 
     waitCount++; 

     lock (lockObj) 
     { 
      Unlock(); 
      Monitor.Wait(lockObj); 
      Lock(); 

      return units[--waitUnitPos]; 
     } 
    } 

    private void Pulse(T unit) 
    { 
     waitCount--; 
     units[waitUnitPos++] = unit; 

     lock (lockObj) 
     { 
      Monitor.Pulse(lockObj); 
     } 
    } 

    private void Lock() 
    { 
     if (Interlocked.CompareExchange(ref lockState, 1, 0) != 0) 
     { 
      SpinLock(); 
     } 
    } 

    private void SpinLock() 
    { 
     SpinWait spinWait = new SpinWait(); 

     do 
     { 
      spinWait.SpinOnce(); 
     } 
     while (Interlocked.CompareExchange(ref lockState, 1, 0) != 0); 
    } 

    private void Unlock() 
    { 
     Interlocked.Exchange(ref lockState, 0); 
    } 

    private void Init(int capacity) 
    { 
     T[] tx = new T[capacity]; 

     for (int i = 0; i < capacity; i++) 
     { 
      tx[i] = unitFactory.Invoke(); 
     } 

     units = tx; 
     this.capacity = capacity; 
    } 
} 
+0

Spinlocks बनाम Mutex http://stackoverflow.com/questions/5869825/when-should-one-use-a-spinlock-instead-of-mutex नहीं कह यह आपकी समस्या का समाधान होगा, लेकिन कुछ करने के लिए इस पर गौर करें। – JNYRanger

+0

क्या आप सीटीओआर के बाहर सेट कैपेसिटी का उपयोग कर रहे हैं? – usr

+0

@usr - इसका इरादा है, लेकिन लॉकिंग को छोड़ने के लिए मैं इसका एक निजी संस्करण प्राप्त करूंगा। ध्यान दें कि कोई भी सुरक्षा उपाय जानबूझकर अनुपस्थित हैं। – Tcqqp

उत्तर

0

इसे फिक्स्ड। मुझे Monitor लॉक के बाहर निम्नलिखित कोड रखना पड़ा।

Lock(); 

return units[--waitUnitPos]; 
संबंधित मुद्दे