首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ReaderWriterLockSlim和异步等待

ReaderWriterLockSlim和异步等待
EN

Stack Overflow用户
提问于 2013-10-29 13:20:14
回答 5查看 19K关注 0票数 49

我对ReaderWriterLockSlim有一些问题。我不明白它是怎么变的。

我的代码:

代码语言:javascript
复制
 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.IsWriteLockHeldtrue,但是当执行到<2>的步骤时,我看到_indexLock.IsWriteLockHeldfalse_indexLock.ExitWriteLock抛出了一个异常SynchronizationLockException,其中有消息“写锁被释放而不被持有”。我做错什么了?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2013-10-29 16:51:11

ReaderWriterLockSlim是一个线程仿射锁类型,所以它通常不能与asyncawait一起使用.

您应该将SemaphoreSlimWaitAsync结合使用,或者(如果您确实需要读取器/写入器锁),使用my 来自AsyncExAsyncReaderWriterLock

票数 82
EN

Stack Overflow用户

发布于 2015-06-29 16:41:30

您可以使用可靠和轻量级的SemaphoreSlim安全地模拟读取器/写入器锁定机制,并保留async/await的优点。创建SemaphoreSlim,给它可用的锁数,相当于将锁定资源以便同时读取的例程数。每个人都会像往常一样请求一个锁。对于您的写作例程,确保它在执行它的操作之前请求所有可用的锁。

这样,您的写作例程将始终单独运行,而您的阅读例程可能只在它们之间共享资源。

例如,假设您有两个阅读例程和一个写作例程。

代码语言:javascript
复制
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)
    }
}

显然,只有在事先知道可以同时运行多少个读取例程时,此方法才能起作用。诚然,太多的代码会使这段代码非常难看

票数 6
EN

Stack Overflow用户

发布于 2020-11-09 18:41:12

不久前,我基于两个AsyncReaderWriterLock为我的项目类实现了SemaphoreSlim。希望能帮上忙。它实现了相同的逻辑(多个读取器和单个Writer),同时支持异步/等待模式。当然,它不支持递归,也没有防止不正确使用的保护:

代码语言:javascript
复制
var rwLock = new AsyncReaderWriterLock();

await rwLock.AcquireReaderLock();
try
{
    // ... reading ...
}
finally
{
    rwLock.ReleaseReaderLock();
}

await rwLock.AcquireWriterLock();
try
{
    // ... writing ...
}
finally
{
    rwLock.ReleaseWriterLock();
}
代码语言:javascript
复制
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();
    }
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19659387

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档