在线程中使用全局字典
本文关键字:全局 字典 线程 | 更新日期: 2023-09-27 18:17:51
假设我有一个Dictionary<string, string>
。字典在我的控制台程序中声明为public static
。
如果我正在使用线程,并且我想从一个线程Dictionary
对此foreach
,但同时另一个线程想要将项目添加到字典中。这将在这里导致错误,因为我们在另一个线程中使用 foreach 循环运行时无法修改我们的Dictionary
。
为了绕过这个问题,我在字典上的每个操作上对同一个静态对象创建了一个锁定语句。
这是绕过此问题的最佳方法吗?我的Dictionary
可能非常大,我可以有很多线程想要在上面寻找它。就像目前一样,事情可能非常缓慢。
尝试使用专为此类场景设计的 ConcurrentDictionary<TKey, TValue>
。
这里有一个关于如何使用它的很好的教程。
最大的问题是:您是否需要foreach
作为快照?
如果答案是"否",那么使用ConcurrentDictionary
,您可能会没事。(剩下的一个问题是,插入和读取的性质是否以不好的方式击中条纹锁,但如果是这种情况,您会发现正常的读取和写入字典的情况更糟(。
但是,由于它GetEnumerator
不提供快照,因此它不会枚举开头和结尾相同的开头。它可能会丢失项目或重复项目。问题是这对你来说是否是一场灾难。
,这将是一场灾难,但不是其他,那么您可以使用Distinct()
过滤掉重复项(无论是键入键还是根据需要同时键入键和值(。
如果您确实需要它成为硬快照,请采用以下方法。
有一个ConcurrentDictionary
(dict
(和一个ReaderWriterLockSlim
(rwls
(。在读取和写入时都获取读取器锁定(是的,即使您正在写入(:
public static void AddToDict(string key, string value)
{
rwls.EnterReadLock();
try
{
dict[key] = value;
}
finally
{
rwls.ExitReadLock();
}
}
public static bool ReadFromDict(string key, out string value)
{
rwls.EnterReadLock();
try
{
return dict.TryGetValue(key, out value);
}
finally
{
rwls.ExitReadLock();
}
}
现在,当我们想要枚举字典时,我们获取写锁(即使我们正在读取(:
public IEnumerable<KeyValuePair<string, string>> EnumerateDict()
{
rwls.EnterWriteLock();
try
{
return dict.ToList();
}
finally
{
rwls.ExitWriteLock();
}
}
通过这种方式,我们获得了用于读取和写入的共享锁,因为ConcurrentDictionary
为我们处理其中涉及的冲突。我们获取用于枚举的独占锁,但时间足够长,以便在列表中获取字典的快照,然后仅在该线程中使用,而不与任何其他线程共享。
使用.NET 4,您可以获得一个花哨的新ConcurrentDictionary。我认为有一些基于 .NET 3.5 的实现四处流传。
是的,当枚举在另一个线程中运行时,更新全局字典时会遇到问题。
解决 方案:
- 要求字典的所有用户在访问对象之前获取互斥锁,并在之后释放锁。
- 使用 .NET 4.0 的 ConcurrentDictionary 类。