我刚刚开始使用Nito.AsyncEx包,AsyncLock
而不是在锁定部分lock() { ... }
中有调用的普通部分(因为我刚刚读到的充分理由async
,你不能lock()
在这种情况下使用)。这是我从 Hangfire 运行的一项工作。让我们称之为“工人”线程。
在另一个线程中,来自 ASP.NET 控制器,我想检查是否有一个线程当前正在锁定部分中执行。如果锁定部分中没有线程,那么我将通过 Hangfire 安排后台作业。如果锁定部分中已经有一个线程,那么我不想安排另一个线程。(是的,这可能听起来有点奇怪,但这是另一个故事)。
有没有办法使用Nito.AsyncEx
对象来检查这个,或者我应该在锁定部分的开头设置一个标志并在最后取消它?
例如,我想这样做:
public async Task DoAJobInTheBackground(string queueName, int someParam)
{
// do other stuff...
// Ensure I'm the only job in this section
using (await _asyncLock.LockAsync())
{
await _aService.CallSomethingAsync());
}
// do other stuff...
}
并从控制器调用的服务中使用我想象的方法IsSomeoneInThereNow()
:
public void ScheduleAJobUnlessOneIsRunning(string queueName, int someParam)
{
if (!_asyncLock.IsSomeoneInThereNow())
{
_backgroundJobClient.Enqueue<MyJob>(x =>
x.DoAJobInTheBackground(queueName, someParam));
}
}
但到目前为止,我只能看到如何使用单独的变量来做到这一点(想象_isAnybodyInHere
是一个线程安全的 bool或者我使用Interlocked
了):
public async Task DoAJobInTheBackground(string queueName, int someParam)
{
// do other stuff...
// Ensure I'm the only job in this section
using (await _asyncLock.LockAsync())
{
try
{
_isAnybodyInHere = true;
await _aService.CallSomethingAsync());
}
finally
{
_isAnybodyInHere = false;
}
}
// do other stuff...
}
并从控制器调用的服务中:
public void ScheduleAJobUnlessOneIsRunning(string queueName, int someParam)
{
if (!_isAnybodyInHere)
{
_backgroundJobClient.Enqueue<MyJob>(x =>
x.DoAJobInTheBackground(queueName, someParam));
}
}
真的感觉应该有更好的方法。医生AsyncLock
说:
您可以使用已取消的 CancellationToken调用 Lock 或 LockAsync 以尝试立即获取 AsyncLock 而无需实际进入等待队列。
但我不明白如何做到这一点,至少使用同步Lock
方法。