同步对单例对象初始化的访问

时间:2018-02-08 19:54:12

标签: c# .net multithreading .net-core get-event-store

我从dotnet核心网络应用程序访问EventStore。所有线程共享一个连接。首次访问时打开连接,我需要确保只有一个线程打开连接。以前我会使用lock,但我无法await方法打开连接。

我发现following snippet的代码看起来应该可以解决这个问题:

public class AsyncLock : IDisposable
{
    private readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);

    public async Task<AsyncLock> LockAsync()
    {
        await _semaphoreSlim.WaitAsync().ConfigureAwait(false);
        return this;
    }

    public void Dispose()
    {
        _semaphoreSlim.Release();
    }
}

并在我的代码中使用它:

private static readonly AsyncLock _mutex = new AsyncLock();
private volatile bool _isConnected = false;
private async Task EstablishConnected()
{
    if (!_isConnected)
    {
        using (await _mutex.LockAsync())
        {
            if (!_isConnected)
            {
                await _connection.ConnectAsync().ConfigureAwait(false);
                _isConnected = true;
            }
        }
    }
}

这是一种合理的方法来同步访问初始化/打开与EventStore的连接吗?

2 个答案:

答案 0 :(得分:2)

原来,nuget library中有一个有用的Github repo和关联的Stephen Cleary,它代替了上面的AsyncLock类。

答案 1 :(得分:1)

我认为你的方法是合理的。但是,如果您正在寻找管理初始化的异步方法,请查看Microsoft.VisualStudio.Threading包中可用的一些对象,例如AsyncLazy。我不认为该软件包可用于.NET核心,但source code在github上并且在MIT许可下。

使用AsyncLazy,您可以执行以下操作:

public class MyEventStoreConsumer
{
    private static readonly Func<Task<IEventStoreConnection>> getConnection;

    static MyEventStoreConsumer()
    {
        var eventStore = EventStoreConnection.Create(...);
        var connection = new AsyncLazy<IEventStoreConnection>(async () =>
        {
            await eventStore.ConnectAsync().ConfigureAwait(false);
            return eventStore;
        });
        getConnection = () => connection.GetValueAsync();
    }
}