【问题标题】:Synchronizing on shared data structure在共享数据结构上同步
【发布时间】:2009-03-21 09:52:53
【问题描述】:

考虑涉及多个线程写入共享数据结构的代码。现在,这些线程中的每一个都将对象写入共享容器,这些对象本质上是唯一的。举一个(虚构的)例子:

class Logger
{
   IDictionary<string, Log> logDictionary = new Dictionary<string, Log>();

   // Method called by several other threads
   void AddLog(Log log)
   {
      logDictionary[log.ID] = log;
   }

   // Method called by a separate thread
   IList GetLog(/*some criteria*/)
   {
      // loop through logDictionary and
      // create an IList based on criteria
   }
}

我清楚地知道,如果多个线程尝试更新相同的“变量”(或槽)导致竞争条件,对共享对象的并发访问可能会成为问题。现在我的问题有 3 个部分。

(1) 如果线程进行盲更新,是否需要同步? (即使他们正在更新相同的插槽/变量)?

(2) 假设每个线程都在写一个唯一的对象,假设它是线程安全的,就不需要同步对共享字典/容器的访问吗?

(3) 另一个线程调用 GetLog() 是否真的会造成问题,即使字典正在被其他线程同时更新?

【问题讨论】:

    标签: c# java multithreading concurrency


    【解决方案1】:

    C# 中的容器类在编写时不是线程安全的,这意味着您必须确保只有一个线程同时访问容器类实例,即使每个线程写入字典中的不同键也是如此。

    对于阅读,字典是线程安全的,即您可以同时从多个线程中读取字典。但是,同时读写是不安全的。

    详情here

    【讨论】:

      【解决方案2】:

      最大的问题是如果任何线程添加/删除字典中的键。这可能会导致内部进行重大重建(很可能会破坏正在进行的任何竞争性读写),所以是的;您确实需要同步访问。如果所有线程都在读取/写入现有密钥,您可能没问题,但我认为这不能保证。

      我不了解 java,但在 C# 中有 ReaderWriterLockSlim 可能(如果您绝对需要它)允许多个并发读取器一个写入器(不是两者) - 但它是通常更简单(有时甚至更快)只是去互斥(通过lock等)。

      编辑

      另外 - 对于强类型字典类型(即泛型等),如果值类型过大,更新将不会互锁;另一个线程可能理论上看到此类值的正在进行的更新。例如 x86 上的 guid 等。

      【讨论】:

        【解决方案3】:

        1) “盲更新”是什么意思?

        2) 否。假设 Dicitonary 是使用哈希表实现的,您需要同步访问以处理哈希冲突、增加表的大小等。您可能能够通过锁定在某些情况下,表而不是整个数据结构的共享锁,但这也有开销。

        3) 取决于更新是否是原子的。

        【讨论】:

        • 盲更新是在不读取变量的情况下更新变量,因为变量之前的值没有意义
        • 如果写了一些东西,那么在某些时候,它会被读取——即使它不是由正在写入的东西(否则,如果它只会被丢弃,为什么还要写它呢?) .如果您不同步,问题是读取可能是错误的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-28
        • 2015-06-23
        • 2021-09-25
        • 2019-10-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多