我正在尝试使用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;
}
}
答案 0 :(得分:0)
修正了它。我必须将以下代码放在Monitor
锁定之外。
Lock();
return units[--waitUnitPos];