C#中的队列同步和操作

时间:2011-07-19 13:22:21

标签: c# multithreading thread-safety queue

如果队列同步:

var _item = Queue.Synchronized(new Queue());

我可以在不使用锁定语句的情况下调用Enqueue和Dequeue等方法吗?

我目前的代码是:

lock (_item.SyncRoot)
{
    _item.Enqueue(obj);
}

我可以线程安全使用:

_item.Enqueue(obj);
var item = _item.Dequeue();

3 个答案:

答案 0 :(得分:4)

Enqueue的调用和Dequeue的调用是线程安全的 但是,您的示例代码不是:
在调用Enqueue和调用Dequeue之间可能存在线程切换。这意味着,item可能是obj之外的另一个实例,或者对Dequeue的调用会引发异常,因为它现在为空。

要使示例代码线程安全,您仍需要明确锁定:

lock(_item.SyncRoot)
{
    _item.Enqueue(obj);
    var item = _item.Dequeue);
}

只有现在才能保证,item引用 - 在所有情况下都等于obj

答案 1 :(得分:4)

这几乎是SynchronizedQueue的作用,但存在问题......通常您需要查看.Count { {1}}在一个原子单元中 - 不检查.Dequeue()(一个单位),然后检查.Count(另一个单位) - 您完全不能信任.Dequeue() 一旦锁定被放弃,如果另一个线程偷走了工作,.Count将抛出。

也许在4.0(.Dequeue())中尝试ConcurrentQueue<T>,或使用.TryDequeue()Queue<T>

答案 2 :(得分:2)

来自MSDN

  

保证线程安全   队列,必须完成所有操作   通过这个包装器。

     

通过集合枚举是   本质上不是线程安全的   程序。即使是收藏品   同步,其他线程仍然可以   修改集合,这会导致   枚举器抛出异常。   确保螺纹安全   枚举,你可以锁定   整个收集   枚举或捕获异常   由其他人做出的改变   线程。

就像John Skeet的回答建议here一样,您可能会更好或使用锁定,因为枚举可能会导致异常。

Gregs answer也谈到了Marc提到的Count不是线程安全的。