无法在锁中等待,如何确保不会从多个线程访问异步变量和方法?

c#

我有以下代码:

public const int ThreadLimitMax = 128;
private static object setThreadLimitLock = new object();
private static SemaphoreSlim totalThreadLimiter = new SemaphoreSlim(ThreadLimit, ThreadLimitMax);
        
public static int ThreadLimit { get; private set; } = 128;

public static async Task SetThreadLimit(int max)
{
    if (max > ThreadLimitMax)
        throw new ArgumentOutOfRangeException(nameof(max), $"Cannot have more than {ThreadLimitMax} threads.");
    if (max < 1)
        throw new ArgumentOutOfRangeException(nameof(max), $"Cannot have less than 1 threads.");

    lock (setThreadLimitLock)
    {
        int difference = Math.Abs(ThreadLimit - max);
        if (max < ThreadLimit)
        {
            for (int i = 0; i < difference; i++)
            {
                await totalThreadLimiter.WaitAsync().ConfigureAwait(false);
            }
        }
        else if (max > ThreadLimit)
        {
            totalThreadLimiter.Release(difference);
        }
        ThreadLimit = max;
    }
}

我正在尝试创建一种方法来修改 totalThreadLimiter 中可用线程的数量。我将最大线程数保留在 ThreadMaxLimit 整数中。

要更改线程数量,我需要确保在更改最大线程的操作完成之前不会访问 ThreadLimit。我还需要确保该方法被阻塞,直到 totalThreadLimiter 完成所有 WaitAsync() 调用。

我怎样才能做到这一点?

回答

lock是围绕 的辅助 API Monitor,它是线程绑定的同步原语,这意味着它不适合与 一起使用await,因为无法保证当您从不完整的异步操作中返回时您将在哪个线程上。

最终,您需要一个异步感知同步原语;最容易获得的是SemaphoreSlim,它具有WaitAsync()用于获取锁的API,带有一个try/finally调用Release().

在问题的代码中,根据代码分支,您要么获取(仅)信号量,要么释放信号量;那几乎肯定是错误的。正确的用法更像是:

await totalThreadLimiter.WaitAsync();
try
{
    // some code with "await" here
}
finally
{
    totalThreadLimiter.Release();
}


以上是无法在锁中等待,如何确保不会从多个线程访问异步变量和方法?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>