为什么std :: mutex在OSX上这么慢?

lei*_*eif 6 c++ macos multithreading

我有以下基准:https://gist.github.com/leifwalsh/10010580

从本质上讲,它会旋转k线程,然后每个线程执行大约1600万次/ k锁定/增量/解锁周期,使用自旋锁和a std::mutex.在OSX上,std::mutex当争用时,它比自旋锁慢得多,而在Linux上它具有竞争力或者更快.

OSX:

spinlock 1:     334ms
spinlock 2:     3537ms
spinlock 3:     4815ms
spinlock 4:     5653ms
std::mutex 1:   813ms
std::mutex 2:   38464ms
std::mutex 3:   44254ms
std::mutex 4:   47418ms
Run Code Online (Sandbox Code Playgroud)

Linux的:

spinlock 1:     305ms
spinlock 2:     1590ms
spinlock 3:     1820ms
spinlock 4:     2300ms
std::mutex 1:   377ms
std::mutex 2:   1124ms
std::mutex 3:   1739ms
std::mutex 4:   2668ms
Run Code Online (Sandbox Code Playgroud)

处理器是不同的,但没有那么不同(OSX是Intel(R)Core(TM)i7-2677M CPU @ 1.80GHz,Linux是Intel(R)Core(TM)i5-2500K CPU @ 3.30GHz),这看起来像库或内核问题.有人知道缓慢的根源吗?

为了澄清我的问题,我理解"有不同的互斥实现可以针对不同的事情进行优化,这不是问题,而是预期的".这个问题是:实现中导致这种情况的实际差异是什么?或者,如果这是一个硬件问题(也许缓存在macbook上只是慢得多),那也是可以接受的.

Dav*_*rtz 12

您只是衡量图书馆选择的交易吞吐量的公平性.该基准是非常人为的,并且会惩罚任何提供任何公平性的企图.

实现可以做两件事.它可以让同一个线程连续两次获取互斥锁,或者它可以更改哪个线程获取互斥锁.这个基准测试严重影响了线程的变化,因为上下文切换需要时间,并且因为对互斥锁进行ping-ponging以及val从缓存到缓存需要时间.

最有可能的是,这只是展示了实施必须做出的不同权衡.它大大奖励那些更愿意将互斥锁返回给最后一个持有它的线程的实现.该基准测试甚至奖励那些浪费CPU来实现的实现!它甚至奖励浪费CPU以避免上下文切换的实现,即使CPU可以执行其他有用的工作!它也不会惩罚可能减慢其他无关线程的核心间流量的实现.

此外,实现互斥体的人通常认为在非竞争情况下的性能比竞争情况下的性能更重要.在这些情况之间可以进行许多权衡,例如假设可能有线程在等待或特别检查是否存在.基准测试仅(或至少,几乎只)测试通常被推销的情况,以支持假定更常见的情况.

坦率地说,这是一个毫无意义的基准,无法识别问题.

具体的解释几乎可以肯定,Linux实现是一个自旋锁/ futex混合,而OSX实现是常规的,相当于锁定一个内核对象.Linux实现的spinlock部分倾向于允许刚刚发布互斥锁的同一个线程再次锁定它,这是你的基准测试得到的重点奖励.

  • 你问缓慢的来源,我正确地解释了缓慢的根源是基准的缺陷. (4认同)
  • 然后我不明白你不明白的是什么.您如何进行这些权衡决定了您在此基准测试中的表现.不同的实现方式使这些权衡方式不同.你说它似乎是一个问题,我在解释为​​什么它不是一个问题(基准测试除外). (3认同)