我有一个函数来清理一些对象以及ReaderWriterLockSlim。但是,我需要ReaderWriterLockSlim锁定为写入器锁,以防止另一个线程在进行清理时读取数据。
ConcurrentDictionary<string, ReaderWriterLockSlim> RwLocks = new ConcurrentDictionary<string, ReaderWriterLockSlim>();
private ReaderWriterLockSlim GetRwLock(string key)
{
return RwLocks.GetOrAdd(key, _ => new ReaderWriterLockSlim());
}
public void CleanUp(string key)
{
ReaderWriterLockSlim rwLock = this.GetRwLock(key);
try
{
rwLock.EnterWriterLock();
// do some other clean up
this.RwLocks.TryRemove(key, out _);
}
finally
{
rwLock.ExitWriterLock();
// It is safe to do dispose here?
// could other thread enter the read lock or writer lock here?
// and the dispose will throw exceptions?
// What is the best practice to do the dispose?
rwLock.Dispose();
}
}我有个主意来包装ReaderWriterLockSlim。你认为它能解决这个问题还是有潜在的风险?
public class ReaderWriterLockSlimWrapper
{
private ReaderWriterLockSlim rwLock;
private volatile bool disposed;
public ReaderWriterLockSlimWrapper()
{
rwLock = new ReaderWriterLockSlim();
disposed = false;
}
private void DisposeInternal()
{
if (!rwLock.IsReadLockHeld && !rwLock.IsUpgradeableReadLockHeld && !rwLock.IsWriteLockHeld)
{
rwLock.Dispose();
}
}
public void Dispose()
{
disposed = true;
DisposeInternal();
}
public void EnterReadLock()
{
rwLock.EnterReadLock();
}
public void ExitReadLock()
{
rwLock.ExitReadLock();
if (disposed)
{
DisposeInternal();
}
}
public void EnterWriteLock()
{
rwLock.EnterWriteLock();
}
public void ExitWriteLock()
{
rwLock.ExitWriteLock();
if (disposed)
{
DisposeInternal();
}
}
}发布于 2022-05-14 06:37:43
您还没有描述打算使用两种机制的特定场景,第一种机制使用CleanUp/GetRwLock方法,第二种机制使用ReaderWriterLockSlimWrapper类。所以我想问题是:
是我的两种安全机制,可以在所有可能的多线程场景中使用,在这些场景中,线程安全和操作原子性是必需的?
答案是否定的,你的两种机制都充满了种族条件,也不能保证原子性。在多线程场景中使用它们会导致未定义的行为,包括但不限于:
预期正确使用的策略( exceptions.
解释为什么你的机制是有缺陷的,这是相当复杂的。一般的解释是,每当您在多线程环境中使用模式if (x.BooleanProperty) x.Method();时,尽管BooleanProperty和Method可能是单独的线程安全的,但您允许第二个线程抢占两个调用之间的当前线程,并使第一个检查的结果无效。
另外,请注意,ReaderWriterLockSlim不是跨进程同步原语。因此,即使您修复了您的机制,然后尝试在web应用程序中使用它们,这些策略仍然可能会被违反,因为web服务器可能会在任意时刻决定回收当前进程并启动一个新进程。在这种情况下,web应用程序可以在两个进程上同时运行,时间跨度为几秒钟甚至几分钟。
https://stackoverflow.com/questions/72224844
复制相似问题