我不确定为什么这段代码不安全。我有一个测试用例来证明它不安全。
List<T> _l = new List<T>();
public void Add(T t)
{
lock (_l)
{
_l.Add(t);
Monitor.PulseAll(_l);
}
}
public T[] RemoveToArray(TimeSpan timeout)
{
lock (_l)
{
if (_l.Count == 0)
{
bool timedout = !Monitor.Wait(_l, timeout);
// no lock
if (timedout)
{
return new T[0];
}
}
// with lock
T[] items = _l.ToArray();
_l.Clear();
return items;
}
}
该函数应该等待一段时间(之后超时)以使新项目到达。当时间到时,返回一个空数组,否则将内部列表中的所有元素排到一个数组中。在测试代码中,我创建了两个Task,一个用来添加,另一个用来移除。
times = 3;
Task[] tasks = new Task[2];
tasks[0] = Task.Factory.StartNew(() =>
{
firstRemoveItems = _l.RemoveToArray(_infinite);
Util.Delay(TimeSpan.FromMilliseconds(10)).Wait();
secondRemoveItems = _l.RemoveToArray(_infinite);
});
tasks[1] = Task.Factory.StartNew(() =>
{
_l.Add(new object());
Util.Delay(TimeSpan.FromMilliseconds(5)).Wait();
for (int i = 1; i < times; i++)
_l.Add(new object());
});
添加了三个项目,但是,项目的总数是 2、3、4。我不太确定问题是什么。我假设等待超时后重新获取锁?