在共享数据结构上同步

时间:2009-03-21 09:52:53

标签: c# java multithreading concurrency

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

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()的调用是否真的会出现问题,即使其他线程同时更新了字典?

3 个答案:

答案 0 :(得分:3)

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

我不知道java,但是在C#中有ReaderWriterLockSlim可能(如果你绝对需要的话)允许多个并发读者一个作者(不是两者) - 但是它通常更简单(有时甚至更快)只是去互斥(通过lock等)。

修改

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

答案 1 :(得分:3)

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

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

详情here

答案 2 :(得分:1)

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

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

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