我想运行一个可能运行几秒钟的清理任务。多个线程可以调用此任务,但我只想运行此任务一次。所有其他的调用都应该跳过。
以下是我目前的实现,但我无法想象.net框架中没有更好的解决方案,从而减少了代码行。
object taskLock;
bool isRunning;
void Task()
{
if (isRunning) return;
try
{
lock (taskLock)
{
if (isRunning) return;
isRunning = true;
}
// Perform the magic
}
finally
{
isRunning = false;
}
}
答案 0 :(得分:1)
是的,有更好的解决方案。您可以使用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
)
如果comparand和location1中的值相等,则值为 存储在location1中。否则,不执行任何操作。比较 和交换操作作为原子操作执行。该 CompareExchange的返回值是location1中的原始值, 是否进行交换