如何保护可能在多线程或异步环境中使用的资源? [英] How to protect resources that may be used in a multi-threaded or async environment?
问题描述
我正在开发一个供各种消费者使用的 C# API.此 API 提供对共享资源(在我的情况下是进行串行通信的硬件)的访问,通常会有几个不同的参与者尝试同时使用它.
I am working on a C# API that is used by a variety of consumers. This API provides access to a shared resource (in my case hardware that does serial communication) , that will often have a few different actors trying to use it concurrently.
我遇到的问题是我的一些消费者希望在多线程环境中使用它 - 每个参与者独立工作并尝试使用资源.一个简单的锁在这里工作正常.但是我的一些消费者更喜欢使用 async-await 和时间切片资源.(据我所知)这需要一个异步锁来将时间片交还给其他任务;在锁上阻塞会停止整个线程.
The issue I have is that some of my consumers will want to use this in a multi-threaded environment - each actor works independently and try to use the resource. A simple lock works fine here. But some of my consumers would prefer to use async-await and time-slice the resource. (As I understand it) this requires an asynchronous lock to yield the timeslice back to other tasks; blocking at a lock would halt that whole thread.
而且我认为使用串行锁充其量是性能不佳,最糟糕的是潜在的竞争条件或死锁.
And I imagine that having serial locks is unperformant at best, and a potential race condition or deadlock at worst.
那么,对于潜在的并发使用,我该如何保护公共代码库中的共享资源?
So how can I protect this shared resource in a common codebase for both potential concurrency usages?
推荐答案
您可以使用 SemaphoreSlim
请求数为 1.SemaphoreSlim
允许使用 WaitAsync
和旧的同步方式:
You can use SemaphoreSlim
with 1 as the number of requests. SemaphoreSlim
allows to lock in both an async
fashion using WaitAsync
and the old synchronous way:
await _semphore.WaitAsync()
try
{
... use shared resource.
}
finally
{
_semphore.Release()
}
您还可以根据 Stephen Toub 的精彩帖子 构建异步协调原语,第 6 部分:AsyncLock.我在我的应用程序中做到了这一点,并允许在同一构造上同时使用同步和异步锁.
You can also write your own AsyncLock
based on Stephen Toub's great post Building Async Coordination Primitives, Part 6: AsyncLock. I did it in my application and allowed for both synchronous and asynchronous locks on the same construct.
用法:
// 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();
}
}
}
这篇关于如何保护可能在多线程或异步环境中使用的资源?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!