我的应用程序中有一个有趣的死锁问题。有一个内存数据存储,它使用ReaderWriterLockSlim来同步读写。其中一种读取方法使用Parallel.ForEach在给定一组过滤器的情况下搜索商店。其中一个过滤器可能需要对同一商店进行恒定时间读取。这是导致死锁的场景:
更新:以下示例代码。用实际方法调用更新的步骤
给定store
ConcreteStoreThatExtendsGenericStore
store.Search(someCriteria)
store.Update()
- ,阻止 Thread1 理想情况下,我想要做的是 not 如果当前线程的祖先线程已经具有相同的锁,则尝试获取读锁。有没有办法做到这一点?或者还有另一种/更好的方法吗?
public abstract class GenericStore<TKey, TValue>
{
private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
private List<IFilter> _filters; //contains instance of ExampleOffendingFilter
protected Dictionary<TKey, TValue> Store { get; private set; }
public void Update()
{
_lock.EnterWriterLock();
//update the store
_lock.ExitWriteLock();
}
public TValue GetByKey(TKey key)
{
TValue value;
//TODO don't enter read lock if current thread
//was started by a thread holding this lock
_lock.EnterReadLock();
value = Store[key];
_lock.ExitReadLock();
return value;
}
public List<TValue> Search(Criteria criteria)
{
List<TValue> matches = new List<TValue>();
//TODO don't enter read lock if current thread
//was started by a thread holding this lock
_lock.EnterReadLock();
Parallel.ForEach(Store.Values, item =>
{
bool isMatch = true;
foreach(IFilter filter in _filters)
{
if (!filter.Check(criteria, item))
{
isMatch = false;
break;
}
}
if (isMatch)
{
lock(matches)
{
matches.Add(item);
}
}
});
_lock.ExitReadLock();
return matches;
}
}
public class ExampleOffendingFilter : IFilter
{
private ConcreteStoreThatExtendsGenericStore _sameStore;
public bool Check(Criteria criteria, ConcreteValueType item)
{
_sameStore.GetByKey(item.SomeRelatedProperty);
return trueOrFalse;
}
}
答案 0 :(得分:1)
目前还不清楚您实际拥有哪种并发,内存和性能要求,因此这里有几个选项。
如果您使用的是.Net 4.0,则可以将Dictionary
替换为ConcurrentDictionary
并删除ReaderWriterLockSlim
。请记住,这样做会减少锁定范围并更改方法语义,允许在枚举(包括其他内容)时更改内容,但另一方面,这将为您提供不会阻塞的线程安全枚举器读或写。您必须确定这是否适合您的情况。
如果您确实需要以这种方式锁定整个集合,则可以支持递归锁定策略(new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion)
),如果您可以将所有操作保留在同一个线程上。并行执行搜索是必要的吗?
或者,您可能只想获取当前值集的快照(锁定该操作),然后针对快照执行搜索。我们无法保证获得最新数据,您将不得不花一点时间进行转换,但也许这对您的情况来说是可以接受的权衡。