我正在研究各种消费者使用的C#API。该API提供对共享资源(在我的情况下为串行通信的硬件)的访问,该资源通常会有几个不同的参与者试图同时使用它。
我遇到的问题是,我的一些消费者希望在多线程环境中使用它- 每个参与者都独立工作并尝试使用资源。一个简单的锁在这里可以正常工作。但是我的一些消费者更喜欢使用异步等待和时间切片资源。(据我了解),这需要异步锁定才能将时间片返回给其他任务;在锁处阻塞会中断整个线程。
而且我认为拥有串行锁最多只能表现不佳,而潜在的竞争状况或最坏的情况就是死锁。
那么,如何针对两种潜在的并发用法在公共代码库中保护此共享资源?
您可以使用SemaphoreSlim1作为请求数。SemaphoreSlim允许async使用WaitAsync和同步方式锁定:
SemaphoreSlim
async
WaitAsync
await _semphore.WaitAsync() try { ... use shared resource. } finally { _semphore.Release() }
您还可以AsyncLock根据Stephen Toub的出色文章《构建异步协调基元》第6部分:AsyncLock编写自己的文章。我在应用程序中做到了这一点,并允许在同一构造上进行同步和异步锁定。
AsyncLock
用法:
// Async using (await _asyncLock.LockAsync()) { ... use shared resource. } // Synchronous using (_asyncLock.Lock()) { ... use shared resource. }
实现方式:
class AsyncLock { private readonly Task<IDisposable> _releaserTask; private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); private readonly IDisposable _releaser; public AsyncLock() { _releaser = new Releaser(_semaphore); _releaserTask = Task.FromResult(_releaser); } public IDisposable Lock() { _semaphore.Wait(); return _releaser; } public Task<IDisposable> LockAsync() { var waitTask = _semaphore.WaitAsync(); return waitTask.IsCompleted ? _releaserTask : waitTask.ContinueWith( (_, releaser) => (IDisposable) releaser, _releaser, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } private class Releaser : IDisposable { private readonly SemaphoreSlim _semaphore; public Releaser(SemaphoreSlim semaphore) { _semaphore = semaphore; } public void Dispose() { _semaphore.Release(); } } }