我最近在一个类似下面的测试中有一个面试问题,我没有太多使用线程开发的经验,有人能帮我建议如何处理这个问题吗?
public class StringQueue
{
private object _lockObject = new object();
private List<string> _items = new List<string>();
public bool IsEmpty()
{
lock (_lockObject)
return _items.Count == 0;
}
public void Enqueue(string item)
{
lock (_lockObject)
_items.Add(item);
}
public string Dequeue()
{
lock (_lockObject)
{
string result = _items[0];
_items.RemoveAt(0);
return result;
}
}
}在上面的实现中,下面的方法线程安全吗?为什么?
public string DequeueOrNull()
{
if (IsEmpty())
return null;
return Dequeue();
}发布于 2011-07-08 06:41:31
在我看来,答案是否定的。
虽然isEmpty()过程会锁定对象,但只要调用返回,它就会被释放--另一个线程可能会在调用IsEmpty()和Dequeue()之间调用DequeueOrNull() (此时对象处于解锁状态),从而删除唯一存在的项,从而使Dequeue()在当时无效。
一种合理的解决方法是将锁放在DequeueOrNull()中的两个语句上,这样在检查之后但在DeQueue()之前没有其他线程可以调用DeQueue()。
发布于 2011-07-08 06:43:01
它不是threadsafe。在标记的行上,Dequeue方法可能是从另一个线程调用的,因此,后续的Dequeue返回一个错误的值:
public string DequeueOrNull()
{
if (IsEmpty())
return null;
/// << it is possible that the Dequeue is called from another thread here.
return Dequeue();
}线程安全代码为:
public string DequeueOrNull()
{
lock(_lockObject) {
if (IsEmpty())
return null;
return Dequeue();
}
}发布于 2011-07-08 06:41:59
不会,因为_items的状态可能会在线程安全的IsEmpty()调用和线程安全的Dequeue()调用之间发生变化。
如下所示进行修复,以确保_items在整个操作过程中处于锁定状态:
public string DequeueOrNull()
{
lock (_lockObject)
{
if (IsEmpty())
return null;
return Dequeue();
}
}注意:根据_lock的implementation,您可能希望通过将IsEmpty()和Dequeue的内部移动到单独的助手函数中来避免双重锁定资源。
https://stackoverflow.com/questions/6617948
复制相似问题