C# 字典的线程安全<;TKey,TValue>;

C# 字典的线程安全<;TKey,TValue>;,c#,C#,如果我初始化一个通用字典一次,并且不允许进一步添加/更新/删除,那么让多个线程在不锁定的情况下读取它是否安全(假设字典是在读取器启动之前初始化的) 非通用哈希表的帮助中有一条注释,说明它对多个读者是安全的,但我没有看到类似的非通用字典的注释是的,如果不再修改字典,它是安全的。线程安全只是读/写方案中的一个问题为了您将来的参考,文档如下: 它说: 字典 可以支持多个读卡器 同时,只要 集合未被修改。即便如此, 在集合中枚举是不正确的 本质上不是线程安全的 程序在罕见的情况下 枚举与写入相抗衡 访

如果我初始化一个通用字典一次,并且不允许进一步添加/更新/删除,那么让多个线程在不锁定的情况下读取它是否安全(假设字典是在读取器启动之前初始化的)


非通用哈希表的帮助中有一条注释,说明它对多个读者是安全的,但我没有看到类似的非通用字典的注释

是的,如果不再修改字典,它是安全的。线程安全只是读/写方案中的一个问题

为了您将来的参考,文档如下:

它说:

字典 可以支持多个读卡器 同时,只要 集合未被修改。即便如此, 在集合中枚举是不正确的 本质上不是线程安全的 程序在罕见的情况下 枚举与写入相抗衡 访问时,集合必须是 在整个枚举过程中锁定。 允许访问集合的步骤 通过多个线程进行读取和 在写作中,你必须实现你自己的 同步


不过,您必须考虑内部状态。在外部,您可能只从字典中读取一个值。但是,您不知道在检索过程中可能会发生什么状态转换。OP@JMarsch在上面发表了评论,并获得了10张赞成票。那么,“内部状态”的事情会如何影响OP的场景呢?
如果我初始化一个通用字典一次,并且不允许进一步添加/更新/删除,那么让多个线程在不锁定的情况下读取它(假设字典在读卡器启动之前初始化)是否安全?
对于字典,是的,Eric Lippert的答案是正确的。从我的评论中需要记住的重要一点是,一般来说,如果只对数据结构进行读取,那么假设它是线程安全的是不够的,因为您不知道读取如何影响内部状态。就字典而言,事实证明,只要在并发读卡器使用它时没有人写入它,读操作就确实是安全的。所以在你的例子中,你初始化它一次,然后只从中读取,你是安全的。谢谢你的澄清。因此,从您的第一条评论中可以采取行动的做法是“理想情况下,仔细检查数据结构的文档或源代码,以查看读取是否是线程安全的”,因为直觉上人们会假设读取是线程安全的,所以当情况并非如此时,数据结构开发人员希望将其记录下来。(为了完整起见,我做了一个脑力练习,并计算出一个哈夫曼树,它可以根据阅读频率动态调整其结构,对于阅读来说可能不是线程安全的。也许这10位投票人也做了他们的练习。)只是想确保我正确理解引用段落中的“即使如此…”部分。如果字典不再被修改(如OP的问题中所提到的),那么枚举也不会成为问题。(2) 如果字典将来可能会被修改,那么即使是
ConcurrentDictionary
枚举也“本质上不是线程安全的过程”。是否正确?@raylou:通常,当枚举处于“运行中”时,无论是多线程还是单线程,都不允许修改集合。并发框架集合(例如,
System.collections.Concurrent.ConcurrentDictionary
)通常允许在枚举期间进行修改。但是,他们通过制作集合的副本并让您枚举副本来实现这一点。复制时,整个集合将被锁定。框架工程师可能会争辩说,这意味着您没有在枚举“运行中”时修改集合(因为在引擎盖下,整个事件在枚举“运行中”时被锁定),但从框架用户的角度来看,枚举正在运行。感谢您的洞察力,Eric&@Brian。值得一提的是,这里引用了“只要集合保持不变,枚举器就保持有效。如果对集合进行了更改,如添加、修改或删除元素,枚举器将不可恢复地失效,其行为也未定义。枚举器对集合没有独占访问权;”顺便说一句,ConcurrentDictionary枚举。