c#中的队列同步和操作

本文关键字:操作 同步 队列 | 更新日期: 2023-09-27 18:02:50

如果队列已同步:

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

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

我当前的代码是:

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

我可以线程安全地使用:

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

c#中的队列同步和操作

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

为了使示例代码线程安全,您仍然需要显式地锁定:
lock(_item.SyncRoot)
{
    _item.Enqueue(obj);
    var item = _item.Dequeue);
}

现在可以保证item在任何情况下都等于obj

这几乎就是SynchronizedQueue所做的,但有一个问题…通常你需要在一个原子单元中检查.Count .Dequeue() -而不是检查.Count(一个单元)然后.Dequeue()(另一个单元)-一旦锁被放弃,你就不能信任.Count ,如果另一个线程窃取了工作,.Dequeue()会抛出。

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

From MSDN

的线程安全队列中,所有的操作都必须完成

枚举一个集合是本质上不是线程安全的过程。即使一个集合是同步后,其他线程仍然可以修改集合,会导致抛出异常的枚举数。期间的线程安全枚举,则可以锁定整个期间的收集枚举或捕获异常由于他人的改变而产生的线程。

正如John Skeet的回答所建议的那样,由于枚举可能会导致异常,因此使用锁可能会更好。

Gregs的回答还谈到了Marc提到的Count不是线程安全的。