【问题标题】:Queue Syncronization and operations in C#C#中的队列同步和操作
【发布时间】:2023-03-08 16:41:01
【问题描述】:
如果队列被同步:
var _item = Queue.Synchronized(new Queue());
我可以在不使用锁定语句的情况下调用 Enqueue 和 Dequeue 等方法吗?
我当前的代码是:
lock (_item.SyncRoot)
{
_item.Enqueue(obj);
}
我可以线程安全地使用吗:
_item.Enqueue(obj);
var item = _item.Dequeue();
【问题讨论】:
标签:
c#
multithreading
thread-safety
queue
【解决方案1】:
对Enqueue 的调用和对Dequeue 的调用是线程安全的。
但是,您的示例代码不是:
在对Enqueue 的调用和对Dequeue 的调用之间可能存在线程切换。这意味着,item 可能是 obj 之外的另一个实例,或者对 Dequeue 的调用会引发异常,因为它现在是空的。
为了使您的示例代码线程安全,您仍然需要显式锁定:
lock(_item.SyncRoot)
{
_item.Enqueue(obj);
var item = _item.Dequeue);
}
只有现在才能保证,item 引用在所有情况下都等于 obj。
【解决方案2】:
来自MSDN
为了保证线程的安全
队列,所有操作都必须完成
仅通过此包装器。
通过集合枚举是
本质上不是线程安全的
程序。即使是一个集合
同步,其他线程仍然可以
修改集合,这会导致
枚举器抛出异常。
为了保证线程安全
枚举,您可以锁定
在整个收集
枚举或捕获异常
由其他人所做的更改导致
线程。
正如 John Skeet 的回答所建议的 here,您可能会更好或使用锁定,因为枚举可能会导致异常。
Gregs answer 还谈到了 Marc 提到的 Count 不是线程安全的。
【解决方案3】:
SynchronizedQueue 几乎就是这样做的,但有一个问题......通常你需要检查.Count 和 .Dequeue() 合二为一原子单元 - 不检查.Count(一个单元)然后检查.Dequeue()(另一个单元) - 一旦锁定被放弃,你就不能信任.Count 根本,.Dequeue() 将如果另一个线程窃取了工作,则抛出。
也许在 4.0 中尝试ConcurrentQueue<T>(使用.TryDequeue()),或者使用Queue<T> 和lock。