我正在试验 C# 中的线程,结果创建了以下类。我试图避免任何竞争条件的情况,但在使用时发生了死锁。
该类使用两种不同的锁,一种用于直接操作的自旋锁,另一种用于等待的 Monitor
锁,以防没有对象准备就绪。我最初使用 EventWaitHandle
,但发现由于 WaitOne
/Set
优先级,竞争条件是不可避免的。
请注意 Monitor.Pulse
不能在 Monitor.Wait
之前,那么还有什么可能导致死锁呢?在5个线程使用容量为4的TestPool
类的情况下,死锁总是在不规则的时刻发生在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;
}
}
最佳答案
修复它。我不得不将以下代码放在 Monitor
锁之外。
Lock();
return units[--waitUnitPos];
关于c# - 对象池类中的死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28840326/