首页 > 解决方案 > 当其中一个线程执行某些操作时,如何使用 SemaphoreSlim 释放所有线程?

问题描述

我有一些我使用的代码SemaphoreSlim

if (!string.IsNullOrEmpty(UserSettings.Token) && !isWithoutRefresh)
{

    if (UserSettings.Expires < ConvertToTimestamp(DateTime.UtcNow.AddMinutes(2)))
    {

        await _locker.LockAsync(async () =>
        {

            if (UserSettings.Expires < ConvertToTimestamp(DateTime.UtcNow.AddMinutes(2)))
            {
                if (Role.Guest.Equals(UserSettings.Role)
                    && !string.IsNullOrEmpty(UserSettings.Email))
                {
                    //TODO: initialize guest session
                }
                else
                {
                    await RefreshToken(httpClient);
                    await AlertService.ShowAsync("Odswiezony");
                }
            }
        });
    }
}

这是我的代码_locker

private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);

public async Task LockAsync(Func<Task> worker)
{
    await _semaphore.WaitAsync();
    try
    {
        await worker();
    }
    finally
    {
        _semaphore.Release();
    }
}

我的问题是,在储物柜内的一个线程执行某些操作后,我能做些什么来异步释放所有线程?因为在这种情况下,每个线程都会同步进行。我想要的解决方案是在我需要刷新令牌时具有逻辑,并且多个线程可以使此操作仅允许它们中的第一个执行此操作,并使其余的线程异步。

标签: c#.netmultithreadingasynchronoussemaphore

解决方案


SemaphoreSlim是为了互斥。它非常适合限制并发性——在这种情况下,一次限制为一个。但你想做的不是互斥。

在这种情况下,您真正​​想要的是一个恰好包含单个项目的异步缓存。AFAIK 目前不存在适当的异步缓存,但我在这里有一个经过部分测试、半验证的缓存。

或者你可以建立你自己的。我建议从异步手动重置事件开始(基于Stephen Toub 的代码或使用我的AsyncEx 库);那么您需要添加决定根据您的到期令牌“重置”它的逻辑。


推荐阅读