2011-01-25 55 views
3

我正在分析大量的多线程代码,我看到了这么多的锁。一些方法将有两个锁在这样的一行:同步代码味道?

ClassA::foo() 
{ 
    lockA.lock(); 
    lockB.lock(); 

    ...//do some stuff 

    lockB.unlock(); 
    lockA.unlock(); 
} 

我的问题是很一般(我不能提供实际的代码)。这是代码味道吗?这通常是不好的做法?我无法证明代码可以被简化,但它看起来好像它是否被正确编码,不需要锁定两件事。锁应该管理一组需要同步的资源,对吧?如果有两个锁与资源管理重叠,那么是否会出现一些死锁问题?

如果您有任何见解,请让我知道。

感谢, JBU

回答

2

这是很常见的一段代码到需要采取两把锁,让本身并不代表一个代码味道。如果这些锁是总是放在一起,这将是一个问题,他们可能应该合并。但是,如果有其他地方的锁是分开拍摄的,那么这种模式很好。

我会在您的代码片段中评论的唯一一件事情是,您最好使用RAII锁类,以使您的代码异常安全并避免其他类型的代码错误(例如意外不会释放锁定一些代码路径)。

+0

如果另一个线程的方法确实是这样ClassB的::巴(){lockB.lock();洛卡。锁();做东西; lockA.unlock(); lockB.unlock();}(注意锁定顺序的逆转)那么存在死锁的条件是不是?也许要添加到您的答案,锁定需要按照一致的顺序完成? – jbu 2011-01-25 16:24:50

+0

是的,锁定需要按照一致的顺序进行。 – 2011-01-25 16:27:55

3

这可能是一种气味,它可能不是,取决于上下文和项目范围。如果你发现自己弄了5个锁来同步排队的列表,那么你可能做错了什么。通常我想在共享资源和锁之间有一个很好的比例。

有时它可能会诱惑锁定更细密的级别(即对列表中的每个项目使用锁而不是整个列表的锁)。重新激发这种冲动,直到一名探查者告诉你这把锁很满足。

通过使用不锁定锁来保护单个资源,但保护商业逻辑的某些部分,您应该可以将多个锁组合成一个锁,以防止争用。你可能会失去一点点的表现,但是如果你能摆脱10个锁,它通常会为它带来的简单性而付出代价。

我想你的问题的答案是在一个问题的形式:为什么你的classA同时使用两个共享资源?通常这是我在设计阶段尝试避免使用某种单一责任原则。通常,共享资源属于某人,并且某人是锁定/解锁资源的单一权限。

有没有什么可以重构的方法来任何方式:

lockA.lock(); 
//some code 
lockA.unlock(); 
lockB.lock(); 
//some other code 
lockB.unlock(); 

一个明确的事情,以确保:应该有订货锁(即洛卡> LOCKB)的预定有限/定义的方式,只锁他们按升序排列。

你不应该得到的

lockA.lock(); 
lockB.lock(); 

的情况和一些其他的代码

lockB.lock(); 
lockA.lock();