在代码块中多次互斥锁定变量是否更有效,或者只是锁定整个代码块?

时间:2016-04-06 06:40:37

标签: c++ mutex

如果我们有以下代码示例:

if (letsDoThis) //bool
{
    sharedVar++; // This is shared across other threads.
          :
    sharedVar++;
          :
    sharedVar++;
          :
    sharedVar++;
          :
    sharedVar++;
}

每个:就像~10行代码(没有慢速函数调用或任何东西)。编写代码是否会更快,这样你就可以锁定整个互联网;如果"阻止(以及if块的内容),或者锁定和解锁每个单独的sharedVar用法?

如果它是"它取决于"类型问题,然后哪种方法(可能作为一个经验法则)最好开始?

最后,您如何确定系统中哪两个运行速度更快? - 跟踪工具是否会以有意义的方式向您显示有用的数据?

2 个答案:

答案 0 :(得分:2)

这取决于(在影响表现的所有其他因素中)

  • 您拥有多少线程和核心(两者的最小值相关)
  • 线程在代码的那一部分(以及锁定互斥锁的其他部分)花费的时间

从单个线程的角度来看,多个锁定和解锁意味着额外的工作,特别是在拥塞时 - 相当昂贵/耗时,并且可能会导致核心之间更多的缓存乒乓。所以它会降低单个线程的性能。但是,如果多次锁定和解锁减少了线程在每次迭代中保存互斥锁的总时间,那么这意味着程序中可以有更多的并行性,并且总体性能随着线程数和CPU内核数量的增加而更好。

两种效果都可以忽略不计,两种效果都可能很重要,如果代码不在程序的热路中,那么首先可能无关紧要。我认为唯一可以做的就是确定在你的情况下更好的是运行两种变体并测量整体吞吐量。如果你没有看到差异,为了简单起见,我可能会使用单个锁并解锁(即使用std::lock_guard)。

你应该问的一般问题是,如果你真的需要在线程之间进行如此多的同步,并且你必须多次同步:如果可以,其他线程看不到共享状态的中间值(哪个如果他们不等彼此,你无法保证,那么为什么不将所有操作合并到共享状态并在块的末尾进行单个操作呢?

当然,如果你的共享状态确实只是一个整数,那么你应该只使用原子并完全摆脱互斥体。

答案 1 :(得分:1)

如果允许后续增量之间的代码从程序逻辑的角度同时运行,那么最好的方法是使用原子计数器。如果在计数器增量需要立即对其他线程可见之前做了什么,那么用release语义(原子增量加屏障)增加,否则 - 用relaxed(只是原子增量)。

如果由于某种原因原子增量不是一个选项,那么在一个循环中同时运行主题代码的简单测试应用程序中对您的互斥锁想法进行基准测试。 google benchmark是一个不错的小型库,可以为您节省一些打字。如果您只有原始Posix线程,则可以借用my old code