C# 'de iş parçacığı kullanmayı deniyorum ve sonuç olarak aşağıdaki sınıfı oluşturdum. Herhangi bir yarış koşulundan kaçınmaya çalıştım, ancak kullanımda bir kilitlenme meydana geldi.Nesne havuzu sınıfındaki kilitlenme
Sınıf, iki farklı kilit, basit işlemler için bir döndürme kilidi ve ayrıca hiçbir nesnenin hazır olmaması durumunda beklemek üzere bir Monitor
kilidi kullanır. Orijinal olarak EventWaitHandle
kullanmıştım, ancak WaitOne
/Set
önceliğinden dolayı yarış koşullarının kaçınılmaz olduğunu keşfettim.
Monitor.Pulse
'un Monitor.Wait
'dan önce gelemediğini unutmayın, bu nedenle kilitlenme neden başka ne olabilir? 5 iş parçacığının 4 kapasiteli bir TestPool
sınıfını kullanması durumunda, kilitlenme her zaman düzensiz bir anda SpinLock
'da gerçekleşir.
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;
}
}
Spinlocks dışlama http://stackoverflow.com/questions/5869825/when-should-one-use-a-spinlock-instead-of-mutex vs Bu sorununuzu çözecektir söyleyerek, ama bir şey değil içine bak. – JNYRanger
SetCapacity'yi ctorun dışında kullanıyor musunuz? – usr
@usr - Bu amaçlanmıştır, ancak kilitlemeyi atlamak için bunun özel bir sürümünü türeteceğim. Herhangi bir önlemin kasıtlı olarak bulunmadığını unutmayın. – Tcqqp