有关方法锁定的最佳实践

3

我有一个需要同步访问的方法,只能允许一个线程同时通过。以下是我的目前实现:

private Boolean m_NoNeedToProceed;
private Object m_SynchronizationObject = new Object();

public void MyMethod()
{
    lock (m_SynchronizationObject)
    {
        if (m_NoNeedToProceed)
            return;

现在我正在考虑对其进行一些修改,如下所示:
private Boolean m_NoNeedToProceed;
private Object m_SynchronizationObject = new Object();

public void MyMethod()
{
    if (m_NoNeedToProceed)
        return;

    lock (m_SynchronizationObject)
    {

在加锁之前进行快速返回是否更好,以便调用线程可以在等待上一个方法调用完成之前继续进行?


2
m_NoNeedToProceed 可以在哪里设置? - Grant Thomas
在其他方法中,例如当用户点击按钮或其他操作时,只是一个条件,有时可以设置以避免运行该方法。 - Tommaso Belluzzo
@Zarathos 可以安全地假设访问 bool、char、byte、sbyte、short、ushort、uint、int、float、引用类型 是原子性的。因此,读/写 bool 是安全的。 - I4V
@I4V 是的,但是在多核CPU上不能保证它们会是“新鲜”的。你需要使用内存屏障来解决这个问题(使用锁、volatile或Thread.MemoryBarrier())。 - Branko Dimitrijevic
3个回答

1

在加锁之前进行快速返回,这样不是更好吗...

不是的。锁不仅是一种互斥机制,还是一个内存屏障1。如果任何并发线程尝试修改变量2,没有锁,就可能引入数据竞争。

顺便说一句,当没有争用时,锁的性能很好,所以你也不会获得太多的性能提升。总之,在性能方面不要做出假设,特别是在“接近底层”的情况下。如有疑问,请测量!

...这样调用线程就可以在不等待上一个方法调用完成的情况下继续进行了吗?

这意味着您持有锁的时间比必要时间长。一旦共享内存不再需要保护(这可能比方法退出早),立即释放锁,就不需要尝试人为地规避它。


1即触发缓存一致性机制,使所有CPU核心看到“相同”的内存。

2例如,一个线程写入变量,但该更改在一个核心的写缓冲区中持续一段时间,因此其他核心上的其他线程不会立即看到它。


0

是的,只要m_NoNeedToProceed没有与之相关的竞争条件。

如果该方法运行时间较长,并且某些线程实际上不需要访问该方法的关键部分。那么最好让它们在不获取锁的情况下提前返回。


只要 m_NoNeedToProceed 是离散设置的,位于方法的关键部分之外并且独立于其他线程,那么就应该没问题。我只是想确保在 MyMethod 内部的一个线程不会切换此布尔值,导致另一个线程过早退出,而实际上它不应该退出。 - Cemafor

0

在锁定之前最好这样做。

m_NoNeedToProceed设为volatile

免责声明: volatile并不能使其线程安全。它只是引起一个屏障,以检查另一个处理器中的值是否已更改。


3
这个东西本身的名字应该就能引起关注。 - Grant Thomas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接