std::mutex 和 QMutex 在 MinGW 64 中的性能(posix 线程版本)

Performance of std::mutex and QMutex in MinGW 64 (posix thread version)

我尝试用std::mutex替换我的应用程序(monte carlo模拟)中的QMutex,令人惊讶的是,计算速度除以3。互斥量locking/unlocking 性能成本从可忽略不计上升到大约 66% 的线程时间。

我深入研究了实现源。我最初认为两者都是 Win32 线程的包装器(std::thread 有一个额外的 pthread 层),但实际上 Qt 没有为互斥量使用任何内核函数,并且有它自己的基于原子变量的内部实现。这个好像快多了。

谢谢

听起来 QMutex 是用自旋锁实现的。回答您的问题:

  • 是的,这是可能的。它有局限性,例如参见 [​​=10=]。
  • 只用原子就可以写一个自旋锁;您不能从标准库中的任何其他内容编写真正的互斥量。
  • 不知道你的算法是做什么的,这很难说。但看起来您可以从阅读本书中获益:Is Parallel Programming Hard, And, If So, What Can You Do About It?。特别是 Counting 章节似乎与您所描述的大致对应。 TL;DR 您将不得不尝试该章中的不同算法,以了解哪种算法更适合您的特定情况。

Qt is not using any kernel functions for the mutexes, and has its own internal implementation based on atomic variables

如果互斥量已经被锁定,Qt 当然会调用 OS 让线程等待 .

这里的想法是,在良好的多线程代码中,等待已锁定的互斥锁的可能性极低; 要优化的常见情况是无竞争的互斥锁,必须尽可能快地保持它。

因此,QMutex 是围绕 Linux futex 系统调用设计的,并使用原子和无锁编程。在无竞争的情况下,不需要系统调用,只需要一些巧妙的原子编程;在有争议的情况下,系统调用 必需的(对 wait/wake 线程),而这正是 Qt 使用的:

有关 QMutex 设计背后的更多信息,请参阅 here

为什么STL不使用类似的方法?我不知道。可能是因为有 native_handle 函数在所有情况下都应该 return "something" ,即使当互斥体被解锁或锁定但没有竞争时,所以它 总是 使用系统调用。

(无论如何,我对 Qt 优于 std::mutex 并不感到惊讶。如果不是,QMutex 将成为 std::mutex 的包装器。)

有趣的是我来这里是为了弄清楚为什么 QMutex 这么慢。至少对于高度满足的情况,与 enterCriticalSection 相比,等待单个对象显得相当慢。 TBB 包装它并且似乎比 windows.

上的 QMutex 快得多