我有一个在多个线程之间共享的字典。每个线程根据给定的键从字典中读取特定值,但是 - 如果字典中不存在该键,则线程需要将其添加到字典中。
为了解决同步问题,我虽然使用了ReaderWriterLockSlim类,它基本上给了我读者 - 作者锁定同步(意思是读者可以并行运行,但一次只能运行一个作者......)但为读者添加了升级选项。使用升级选项,我可以测试给定的密钥是否已经在字典中,如果没有 - 升级锁并写入它,承诺每个密钥只添加一个。
我的问题是我无法一次创建两个可升级的锁 - 这意味着这个解决方案并不好...... :(
有人可以向我解释为什么微软选择以这种方式实施可升级锁定(我一次不能拥有多个可升级锁定......),并且让我知道如何通过以下方式实现可升级锁定我自己\给我另一个想法来同步我的共享字典?
答案 0 :(得分:8)
如果您使用的是.NET 4.0,请不要使用ConcurrentDictionary
答案 1 :(得分:4)
我不知道为什么ReaderWriterLockSlim
以这种方式实施。我怀疑有充分的理由。
为什么不使用ConcurrentDictionary?然后你不必担心显式锁定。
那就是说,我看不出有多个可升级读卡器锁可以帮到你。请考虑以下情形:
Thread1 enters the lock in upgradeable mode
Thread2 enters the lock in upgradeable mode
Thread1 searches for "xyzzy" and doesn't find it
Thread2 searches for "xyzzy" and doesn't find it
Thread2 upgrades to a write lock
Thread1 waits to upgrade to a write lock
Thread2 updates and releases the lock
Thread1 acquires the write lock and overwrites what Thread2 had written
为了防止Thread1覆盖Thread2所做的事情,你必须写下这个逻辑:
Enter upgradable read lock
if (!dict.TryGetValue(...))
{
Enter write lock
if (!dict.TryGetValue(...)) // extra check required!
{
}
}
当没有可升级的锁时,这正是你必须做的。
答案 2 :(得分:1)
存在UpgradeableReadLock,因此您无需在获取写锁定之前释放读锁定。它可以让你这样做:
locker.EnterUpgradeableReadLock();
...
locker.EnterWriteLock();
...
而不是
locker.EnterReadLock();
...
locker.ExitReadLock();
locker.EnterWriteLock();
...
由于它是一个ReaderWriter锁,您可能在任何给定时间仍然只有一个写入程序,可升级的读取锁执行。这意味着这两者并不等同;第一个允许其他调用者潜入,但允许读取部分中的并发。
如果您有可以使用ReadLocks进行大多数读取,而使用UpgradeableRead进行数据更新/插入的情况,这就是目的。如果您的所有数据访问都是潜在的编写者,那么这可能不会起作用,您可以在写入时使用简单的锁定(对象)来强制执行添加/更新时的独占访问。
答案 3 :(得分:-2)
听起来你可能没有使用这个问题的最佳解决方案。
示例:
protected static object _lockObj = new object();
if(_dictionary.ContainsKey(key))
{
return _dictionary[key];
}
else
{
lock(_lockObj)
{
if(_dictionary.ContainsKey(key))
return _dictionary[key];
_dictionary.Add(key, "someValue");
return "someValue";
}
}
如果您使用的是.NET 4,请尝试使用其他人提到的ConcurrentDictionary类。