【发布时间】:2021-05-25 10:16:14
【问题描述】:
我有三个独立的代码在不同的线程中运行。
线程任务 1:从设备读取数据并将其写入ConcurrentDictionary。
线程任务2:将ConcurrentDictionary中的数据作为单独的文件写入计算机。
我在论坛上读过很多帖子说并发字典对于单独的线程是安全的。我还读到有锁定情况。事实上,我的脑海中出现了不止一个问号。
并发字典需要加锁吗?在哪些情况下需要锁定?如果需要加锁怎么办?以下方式使用会导致什么问题?
线程代码 1:每秒都有数据进来。
public void FillModuleBuffer(byte[] buffer, string IpPort)
{
if (!CommunicationDictionary.dataLogList.ContainsKey(IpPort))
{
CommunicationDictionary.dataLogList.TryAdd(IpPort, buffer);
}
}
线程代码 2: 下面的代码在计时器中工作。定时器持续时间为 200 毫秒。
if (CommunicationDictionary.dataLogList.ContainsKey(IpPort))
{
using (stream = File.Open(LogFilename, FileMode.Append, FileAccess.Write))
{
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write(CommunicationDictionary.dataLogList[IpPort]);
writer.Flush();
writer.Close();
CommunicationDictionary.dataLogList.TryRemove(IpPort,out _);
}
}
}
注意:为了清楚起见,代码已被简化。
注2:在那之前我用过Dictionary。我遇到了一个非常不同的问题。在活动状态下,2-3 小时后,即使Dictionary 中没有数据,我也会收到数组超出索引范围的错误。
【问题讨论】:
-
Thread code 1:删除ContainsKey检查。它没有任何用处。 -
Thread code 2:将ContainsKey检查替换为TryGetValue。或者,更好的是,考虑删除 both 并使用TryRemoveonly。请注意,如果您这样做,您将需要考虑如果您从字典中删除该项目并且流写入失败会发生什么。 -
@SomeBody 这可能是真的 - 但 OP 的代码不是 100% 安全的(例如,如果第三个线程从并发字典中删除项目,那么线程代码 2 最终将失败)。
-
如果有一种方法绝对安全,而 可能 是安全的,我通常会鼓励“绝对安全”的方法。因为代码会随着时间而改变。
-
Saklanmaz 您可能有兴趣阅读我对When should I use ConcurrentDictionary and Dictionary? 的看法。简而言之,
ConcurrentDictionary可以看作是对受lock保护的普通Dictionary的性能优化。但是你在性能上获得了什么,你就失去了灵活性。ConcurrentDictionary可以用线程安全原子地做的事情是有限的。
标签: c# dictionary locking concurrentdictionary