整数的无锁多线程
Lockless multithreading of an integer
假设有一个函数在任何给定时间只能由一个线程执行,其余的只是 return(因为特定状态已经在处理),最好的方法是什么要做到这一点?
public void RunOnce()
{
if(Interlocked.Exchange(ref m_isRunning, 1) == 1)
return;
// Run code that should only be executed once
// What mechanism do we use here to ensure thread safety?
Volatile.Write(ref m_isRunning, 0);
}
如果 m_isRunning 是一个状态(即表示枚举的整数),是否会应用相同的机制?
你问题中的代码恕我直言是线程安全的,但总的来说
Interlocked.CompareExchange
方法比 Interlocked.Exchange
方法更灵活地实现无锁多线程。以下是我更喜欢对 RunOnce
方法进行编码的方式:
int _lock; // 0: not acquired, 1: acquired
public void RunOnce()
{
bool lockTaken = Interlocked.CompareExchange(ref _lock, 1, 0) == 0;
if (!lockTaken) return;
try
{
// Run code that should be executed by one thread only.
}
finally
{
bool lockReleased = Interlocked.CompareExchange(ref _lock, 0, 1) == 1;
if (!lockReleased)
throw new InvalidOperationException("Could not release the lock.");
}
}
我的建议是使用 Monitor
class:
object _locker = new();
public void RunOnce()
{
bool lockTaken = Monitor.TryEnter(_locker);
if (!lockTaken) return;
try
{
// Run code that should be executed by one thread only.
}
finally { Monitor.Exit(_locker); }
}
...或 SemaphoreSlim
class if you prefer to :
SemaphoreSlim _semaphore = new(1, 1);
public void RunOnce()
{
bool lockTaken = _semaphore.Wait(0);
if (!lockTaken) return;
try
{
// Run code that should be executed by one thread only.
}
finally { _semaphore.Release(); }
}
恕我直言,它使您的代码更清晰。
假设有一个函数在任何给定时间只能由一个线程执行,其余的只是 return(因为特定状态已经在处理),最好的方法是什么要做到这一点?
public void RunOnce()
{
if(Interlocked.Exchange(ref m_isRunning, 1) == 1)
return;
// Run code that should only be executed once
// What mechanism do we use here to ensure thread safety?
Volatile.Write(ref m_isRunning, 0);
}
如果 m_isRunning 是一个状态(即表示枚举的整数),是否会应用相同的机制?
你问题中的代码恕我直言是线程安全的,但总的来说
Interlocked.CompareExchange
方法比 Interlocked.Exchange
方法更灵活地实现无锁多线程。以下是我更喜欢对 RunOnce
方法进行编码的方式:
int _lock; // 0: not acquired, 1: acquired
public void RunOnce()
{
bool lockTaken = Interlocked.CompareExchange(ref _lock, 1, 0) == 0;
if (!lockTaken) return;
try
{
// Run code that should be executed by one thread only.
}
finally
{
bool lockReleased = Interlocked.CompareExchange(ref _lock, 0, 1) == 1;
if (!lockReleased)
throw new InvalidOperationException("Could not release the lock.");
}
}
我的建议是使用 Monitor
class:
object _locker = new();
public void RunOnce()
{
bool lockTaken = Monitor.TryEnter(_locker);
if (!lockTaken) return;
try
{
// Run code that should be executed by one thread only.
}
finally { Monitor.Exit(_locker); }
}
...或 SemaphoreSlim
class if you prefer to
SemaphoreSlim _semaphore = new(1, 1);
public void RunOnce()
{
bool lockTaken = _semaphore.Wait(0);
if (!lockTaken) return;
try
{
// Run code that should be executed by one thread only.
}
finally { _semaphore.Release(); }
}
恕我直言,它使您的代码更清晰。