我的应用程序中有一个有趣的死锁问题。有一个内存数据存储,它使用 ReaderWriterLockSlim 来同步读取和写入。其中一个读取方法使用 Parallel.ForEach 来搜索给定一组过滤器的商店。其中一个过滤器可能需要对同一存储进行恒定时间读取。这是产生死锁的场景:
更新:下面的示例代码。使用实际方法调用更新的步骤给定的
单例实例store
ConcreteStoreThatExtendsGenericStore
- Thread1在存储上获得读锁 -
store.Search(someCriteria)
- Thread2尝试使用写锁更新存储 -
store.Update()
- 阻塞Thread1 - Thread1对存储执行 Parallel.ForEach 以运行一组过滤器
- Thread3(由Thread1的 Parallel.ForEach 产生)尝试对存储进行恒定时间读取。它试图获得读锁,但被Thread2的写锁阻塞。
- Thread1无法完成,因为它无法加入Thread3。 Thread2无法完成,因为它被Thread1阻塞。
理想情况下,如果当前线程的祖先线程已经拥有相同的锁,我想做的不是尝试获取读锁。有没有办法做到这一点?还是有另一种/更好的方法?
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;
}
}