如何保护可能在multithreading或asynchronous环境中使用的资源?
我正在研究一个被各种消费者使用的C#API。 这个API提供对共享资源的访问(在我的情况下是用来进行串行通信的硬件),通常会有几个不同的参与者试图同时使用它。
我的问题是,我的一些消费者会想要在multithreading环境中使用它 – 每个angular色独立工作,并尝试使用资源。 一个简单的锁在这里工作正常。 但是,我的一些消费者更喜欢使用asynchronous等待和时间片资源。 (据我所知)这需要一个asynchronouslocking产生时间片回到其他任务; 在锁上阻塞会阻止整个线程。
而且我认为有串行锁是最好的,最坏的情况是潜在的竞争条件或死锁。
那么我怎样才能保护共享代码库中的共享资源,以实现潜在的并发使用?
您可以使用SemaphoreSlim
和1作为请求数量。 SemaphoreSlim
允许使用WaitAsync
和旧的同步方式来lockingasync
:
await _semphore.WaitAsync() try { ... use shared resource. } finally { _semphore.Release() }
你也可以编写你自己的AsyncLock
基于Stephen Toub的伟大的AsyncLock
构buildasynchronous协调基元,第6部分:AsyncLock 。 我在我的应用程序中做了它,并允许在同一个构造上同步和asynchronouslocking。
用法:
// 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(); } } }