如何保护可能在多线程或异步环境中使用的资源? [英] How to protect resources that may be used in a multi-threaded or async environment?

查看:17
本文介绍了如何保护可能在多线程或异步环境中使用的资源?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个供各种消费者使用的 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆