无法在锁中等待,如何确保不从多个线程访问异步变量和方法?
Unable to await in a lock, how do I ensure async variable and method are not accessed from multiple threads?
我有以下代码:
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();
}
我有以下代码:
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();
}