【问题标题】: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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-01-17
          • 1970-01-01
          • 1970-01-01
          • 2011-02-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多