我对ReaderWriterLockSlim有一些问题。我不明白它是怎么变的。
我的代码:
private async Task LoadIndex()
{
if (!File.Exists(FileName + ".index.txt"))
{
return;
}
_indexLock.EnterWriteLock();// <1>
_index.Clear();
using (TextReader index = File.OpenText(FileName + ".index.txt"))
{
string s;
while (null != (s = await index.ReadLineAsync()))
{
var ss = s.Split(':');
_index.Add(ss[0], Convert.ToInt64(ss[1]));
}
}
_indexLock.ExitWriteLock();<2>
}当我在<1>输入写锁时,在调试器中我可以看到_indexLock.IsWriteLockHeld是true,但是当执行到<2>的步骤时,我看到_indexLock.IsWriteLockHeld是false,_indexLock.ExitWriteLock抛出了一个异常SynchronizationLockException,其中有消息“写锁被释放而不被持有”。我做错什么了?
发布于 2013-10-29 16:51:11
ReaderWriterLockSlim是一个线程仿射锁类型,所以它通常不能与async和await一起使用.
您应该将SemaphoreSlim与WaitAsync结合使用,或者(如果您确实需要读取器/写入器锁),使用my 来自AsyncEx或AsyncReaderWriterLock。
发布于 2015-06-29 16:41:30
您可以使用可靠和轻量级的SemaphoreSlim安全地模拟读取器/写入器锁定机制,并保留async/await的优点。创建SemaphoreSlim,给它可用的锁数,相当于将锁定资源以便同时读取的例程数。每个人都会像往常一样请求一个锁。对于您的写作例程,确保它在执行它的操作之前请求所有可用的锁。
这样,您的写作例程将始终单独运行,而您的阅读例程可能只在它们之间共享资源。
例如,假设您有两个阅读例程和一个写作例程。
SemaphoreSlim semaphore = new SemaphoreSlim(2);
async void Reader1()
{
await semaphore.WaitAsync();
try
{
// ... reading stuff ...
}
finally
{
semaphore.Release();
}
}
async void Reader2()
{
await semaphore.WaitAsync();
try
{
// ... reading other stuff ...
}
finally
{
semaphore.Release();
}
}
async void ExclusiveWriter()
{
// the exclusive writer must request all locks
// to make sure the readers don't have any of them
// (I wish we could specify the number of locks
// instead of spamming multiple calls!)
await semaphore.WaitAsync();
await semaphore.WaitAsync();
try
{
// ... writing stuff ...
}
finally
{
// release all locks here
semaphore.Release(2);
// (oh here we don't need multiple calls, how about that)
}
}显然,只有在事先知道可以同时运行多少个读取例程时,此方法才能起作用。诚然,太多的代码会使这段代码非常难看。
发布于 2020-11-09 18:41:12
不久前,我基于两个AsyncReaderWriterLock为我的项目类实现了SemaphoreSlim。希望能帮上忙。它实现了相同的逻辑(多个读取器和单个Writer),同时支持异步/等待模式。当然,它不支持递归,也没有防止不正确使用的保护:
var rwLock = new AsyncReaderWriterLock();
await rwLock.AcquireReaderLock();
try
{
// ... reading ...
}
finally
{
rwLock.ReleaseReaderLock();
}
await rwLock.AcquireWriterLock();
try
{
// ... writing ...
}
finally
{
rwLock.ReleaseWriterLock();
}public sealed class AsyncReaderWriterLock : IDisposable
{
private readonly SemaphoreSlim _readSemaphore = new SemaphoreSlim(1, 1);
private readonly SemaphoreSlim _writeSemaphore = new SemaphoreSlim(1, 1);
private int _readerCount;
public async Task AcquireWriterLock(CancellationToken token = default)
{
await _writeSemaphore.WaitAsync(token).ConfigureAwait(false);
await SafeAcquireReadSemaphore(token).ConfigureAwait(false);
}
public void ReleaseWriterLock()
{
_readSemaphore.Release();
_writeSemaphore.Release();
}
public async Task AcquireReaderLock(CancellationToken token = default)
{
await _writeSemaphore.WaitAsync(token).ConfigureAwait(false);
if (Interlocked.Increment(ref _readerCount) == 1)
{
try
{
await SafeAcquireReadSemaphore(token).ConfigureAwait(false);
}
catch
{
Interlocked.Decrement(ref _readerCount);
throw;
}
}
_writeSemaphore.Release();
}
public void ReleaseReaderLock()
{
if (Interlocked.Decrement(ref _readerCount) == 0)
{
_readSemaphore.Release();
}
}
private async Task SafeAcquireReadSemaphore(CancellationToken token)
{
try
{
await _readSemaphore.WaitAsync(token).ConfigureAwait(false);
}
catch
{
_writeSemaphore.Release();
throw;
}
}
public void Dispose()
{
_writeSemaphore.Dispose();
_readSemaphore.Dispose();
}
}https://stackoverflow.com/questions/19659387
复制相似问题