我知道Boost支持互斥锁和lock_guard,可以用来实现关键部分。
但是Windows有关键部分的特殊API(请参阅EnterCriticalSection和LeaveCriticalSection),它比互斥锁更快(对于很少竞争的短代码段)。
因此我的问题 - 在Boost中可以利用这个API,并在其他平台上回退到基于spinlock / mutex / futex的实现吗?
答案 0 :(得分:2)
简单的答案是否定的。
以下是一些相关背景from an old mailing list thread:
顺便说一句。我同意互斥是一个通用解决方案来自
性能观点。但公平地说 - CS更简单 设计。我相信支持他们的可能性应该是 最小 考虑到了。
这是有人指出我的文章。结论是 只有在以下情况下CS才会更快:
- 此过程总共少于8个主题。
- 你没有在后台跑步。
- 你不在双处理器机器上。
对我而言,这意味着简单的测试可以产生良好的CS性能 结果,但任何现实世界的计划都会变得更好 互斥。
我不支持CS实施。但是,我 最初选择不是出于以下原因:
- 使用PIMPL可以获得构建和破坏命中 习惯用法或者你必须在Boost.Threads标题中包含Windows.h, 我根本不想这样做。 (这可以解决 从MSDN模拟CS ala OPTEX。)
- 根据这篇研究论文大多数程序不会受益 CS设计。
- 编写一个(非可移植的)critical_section类是微不足道的 如果您真的可以使用它,请遵循Mutex模型。
现在我认为我做出了正确的选择,尽管我们在路上 可能会将实现更改为使用临界区或OPTEX。
比尔肯普夫
答案 1 :(得分:2)
作为帮助维护Boost.Thread的人,以及未能将事件对象导入Boost.Thread的人,我认为从未添加过关键部分,也不会因为以下原因而添加到Boost中:
使用boost :: atomic和boost :: condition_variable很容易构建一个Win32临界区,所以它真的不值得拥有官方版本。这可能是你能想象到的最复杂的一个,但是极其可配置,包括准备好constexpr(不要问!):https://github.com/ned14/boost.outcome/blob/master/include/boost/outcome/v1/spinlock.hpp#L331
您可以通过匹配(基本)可锁定概念并使用原子compare_exchange(非x86 / x64)或原子交换(x86 / x64)来构建自己的,然后使用关键部分周围的lock_guard来获取它。
有些人可能反对win32关键部分不是这个。我担心它是:它只是旋转原子进行旋转计数,然后懒惰地尝试分配一个win32事件对象,然后等待它。没什么特别的。
尽管您可能认为关键部分(真正的用户模式互斥体)更好/更快/更好,但它们可能并不像您想象的那么好。在内部使用win32信号量作为内核等待对象的boost :: mutex是一个巨大的重量级东西,因为需要在通用使用上下文中模拟线程取消和表现良好。编写一个并发结构的 easy 对于某些单例用例来说比另一个更快,但编写并发结构非常困难:
即使您管理了上述所有这三项,仍然是不够的:您还需要对最坏情况下的进展顺序提供一些保证,因此锁定,等待和解锁的某些模式是否会产生可预测的结果。这就是为什么在狭窄的用例场景中线程设施看起来看起来很慢的原因,所以Boost.Thread很多,因为STL看起来比手动锁定代码慢得多,比如说无条件的用例。
Boost.Thread已经在用户模式下做了大量工作,以避免在Windows上进入内核休眠状态。在POSIX上,任何主要的pthreads实现也做了大量的工作来避免内核休眠,因此Boost.Thread不会复制那项工作。换句话说,关键部分在扩展到加载行为方面没有任何好处,但不可避免的是Boost.Thread v4特别是在Windows上做了大量的工作,一个天真的实现没有(Boost.Thread的计划重写是巨大的)在Windows上更高效,因为它可以采用Windows Vista或更高版本。)
答案 2 :(得分:1)
因此,看起来默认的Boost互斥锁并不支持它,但asio::detail::mutex
会支持它。
所以我最终使用了它:
#include <boost/asio/detail/mutex.hpp>
#include <boost/thread.hpp>
using boost::asio::detail::mutex;
using boost::lock_guard;
int myFunc()
{
static mutex mtx;
lock_guard<mutex> lock(mtx);
. . .
}