如何避免在不阻塞的情况下并发调用方法
本文关键字:情况下 并发 调用 方法 何避免 | 更新日期: 2023-09-27 18:35:44
我想运行一个可能运行几秒钟的清理任务。多个线程可以调用此任务,但我只想运行此任务一次。所有其他调用都应跳过。
以下是我当前的实现,但我无法想象 .net 框架中没有更好的解决方案,导致代码行数减少。
object taskLock;
bool isRunning;
void Task()
{
if (isRunning) return;
try
{
lock (taskLock)
{
if (isRunning) return;
isRunning = true;
}
// Perform the magic
}
finally
{
isRunning = false;
}
}
是的,有一个更好的解决方案。您可以使用Interlocked.CompareExchange,代码变得更加简单和无锁:
class Worker
{
private volatile int isRunning = 0;
public void DoWork()
{
if (isRunning == 0 && Interlocked.CompareExchange(ref isRunning, 1, 0) == 0)
{
try
{
DoTheMagic();
}
finally
{
isRunning = 0;
}
}
}
private void DoTheMagic()
{
// do something interesting
}
}
在这种情况下,Interlocked.CompareExchange
作为原子操作(伪代码)执行以下操作:
wasRunning = isRunning;
if isRunning = 0 then
isRunning = 1
end if
return wasRunning
从 MSDN 文档:
public static int CompareExchange(
ref int location1,
int value,
int comparand
)
如果比较和位置 1 中的值相等,则值为 存储在位置 1。否则,不执行任何操作。比较 交换操作作为原子操作执行。这 比较交换的返回值是位置 1 中的原始值, 是否进行交换