用 c + + 11等价物替换掉升级: : 线程和升级: : 互斥对象是否明智?

动机: 我之所以考虑这个问题,是因为我的天才项目经理认为助推是另一种依赖,而这种依赖是可怕的,因为“你依赖它”(我试图解释助推的质量,但过了一段时间后放弃了: ()。我想这么做的一个小原因是我想学习 c + + 11的特性,因为人们会开始用它写代码。 所以:

  1. #include<thread> #include<mutex>和 提高等价物?
  2. 你认为用 c + + 11代替 Boost 是个好主意吗
    我的用法是原始的,但有没有例子,当性病没有 提供什么激励? 或者(亵渎)反之亦然?

附言。 我使用海湾合作委员会,所以标题有。

45205 次浏览

std::thread在很大程度上是以 boost::thread为模型的,有些不同:

  • 升级的不可复制的、一个句柄映射到一个 OS 线程的语义被保留。但是这个线程是可移动的,以允许从工厂功能返回线程,并将其放入容器中。
  • 这项建议增加了取消 boost::thread,这是一个重大的复杂性。这个变化不仅对线程有很大的影响,而且对 C + + 线程库的其他部分也有很大的影响。人们认为,这种巨大的变化是合理的,因为有利可图。
    • 线程析构函数现在必须在分离之前调用 Cancel,以避免在取消父线程时意外泄漏子线程。
    • 现在需要一个显式的分离成员来启用不取消的分离。
  • 线程句柄和线程标识的概念被分为两个类(它们在 boost::thread中是相同的类)。这是为了支持更容易操作和存储线程标识。
  • 已经添加了创建线程 id 的能力,这个线程 id 可以保证与其他可接合线程进行比较(boost::thread没有这个功能)。这对于那些想知道它是否与前一个调用由同一个线程执行的代码来说非常方便(递归互斥对象是一个具体的例子)。
  • 存在一个“后门”来获取本机线程句柄,以便客户机可以使用底层操作系统操作线程(如果需要的话)。

这是从2007年开始的,所以有些观点不再有效: boost::thread现在有一个 native_handle函数,而且,正如评论者指出的,std::thread不再有取消。

我找不到 boost::mutexstd::mutex之间有任何显著差异。

Boost. Thread 和 C + + 11标准线程库有几个不同之处:

  • Boost 支持线程取消,而 C + + 11线程不支持
  • C + + 11支持 std::async,但 Boost 不支持
  • Boost 有一个 boost::shared_mutex用于多读取器/单写入器锁定。类似的 std::shared_timed_mutex仅在 C + + 14(N3891)时可用,而 std::shared_mutex仅在 C + + 17(N4508)时可用。
  • C + + 11超时和 Boost 超时是不同的(尽管现在 Boost 应该很快就会改变,Chrono 已经被接受)。
  • 有些名称是不同的(例如 boost::unique_futurestd::future)
  • std::thread的参数传递语义不同于 boost::thread——-Boost 使用 boost::bind,它需要可复制的参数。std::thread允许像 std::unique_ptr这样的仅移动类型作为参数传递。由于使用了 boost::bind,嵌套绑定表达式中占位符(如 _1)的语义也可能不同。
  • 如果没有显式调用 join()detach(),那么 boost::thread析构函数和赋值操作符将对被销毁/赋值的线程对象调用 detach()。对于 C + + 11 std::thread对象,这将导致调用 std::terminate()并中止应用程序。

为了澄清关于仅移动参数的问题,下面是有效的 C + + 11,并在启动新线程时将 int的所有权从临时 std::unique_ptr转移到 f1的参数。但是,如果您使用 boost::thread,那么它将无法工作,因为它在内部使用 boost::bind,而且不能复制 std::unique_ptr。与 GCC 一起提供的 C + + 11线程库中也存在一个 bug,它阻止了这种工作,因为它在实现中也使用了 std::bind

void f1(std::unique_ptr<int>);
std::thread t1(f1,std::unique_ptr<int>(new int(42)));

如果你正在使用 Boost,那么如果你的编译器支持的话,你可以相对轻松地切换到 C + + 11线程(例如,Linux 上最新版本的 GCC 在 -std=c++0x模式下有一个基本完整的 C + + 11线程库实现)。

如果您的编译器不支持 C + + 11线程,那么您可以获得第三方实现,如 线,但这仍然是一个依赖项。

不迁移到 std::thread有一个原因。

如果你使用静态链接,由于这些 gcc 错误/特性,std::thread将变得不可用:

也就是说,如果您调用 std::thread::detachstd::thread::join,它将导致异常或崩溃,而 boost::thread在这些情况下工作正常。

我尝试从 std 中使用 share _ ptr 来代替 Boost,实际上我在这个类的 gcc 实现中发现了一个 bug。我的应用程序崩溃了,因为析构函数被调用了两次(这个类应该是线程安全的,不应该产生这样的问题)。在移动到 Boost: : share _ ptr 之后,所有问题都消失了。目前 C + + 11的实现还不成熟。

Boost 还有更多功能。例如,std 版本中的 Header 没有为流提供序列化器(即 cout < < period)。Boost 有许多库使用它自己的等价物,但是不与标准版本协作。

总而言之,如果您已经有一个使用升级编写的应用程序,那么保持代码的原样会更安全,而不是花费一些精力转向 C + + 11标准。

在 VisualStudio2013中,std::mutex的表现似乎与 boost::mutex不同,这给我带来了一些问题(参见 这个问题)。

企业案例

如果你正在为企业编写软件,这些企业需要在中等到大量的操作系统上运行,因此需要在这些操作系统上构建各种编译器和编译器版本(尤其是相对较老的版本) ,我的建议是暂时完全远离 C + + 11。这意味着您不能使用 std::thread,我建议您使用 boost::thread

基本/科技创业个案

如果你正在为一两个操作系统编写代码,你肯定知道你只需要使用一个现代编译器来编译代码,这个编译器主要支持 C + + 11(例如 VS2015,GCC 5.3,Xcode 7) ,而且你还没有依赖于升级库,那么 std::thread可能是一个不错的选择。

我的经验

就我个人而言,我更倾向于坚固的、使用频繁的、高度兼容的、高度一致的库,比如 ost 和一个非常现代的替代品。对于复杂的编程主题(如线程)来说尤其如此。此外,我长期以来在 boost::thread上取得了巨大的成功(并且在一般情况下得到了提升) ,跨越了大量的环境、编译器、线程模型等等。当它是我的选择,我选择推动。

关于在 C + + 17中添加的 std: : share _ mutex

这里的其他答案提供了一个非常好的差异的总体概述。然而,有几个问题与 std::shared_mutex的助推解决。

  1. 可升级的静默数。这些在 std::thread中都没有。它们允许将读取器升级为编写器 不能让其他作家抢在你前面。它们允许您在读模式下对大型计算进行预处理(例如,对数据结构进行重新索引) ,然后升级到 write 以应用重新索引,同时只在短时间内保持写锁。

  2. 公平。如果你持续使用 std::shared_mutex进行阅读活动,你的作者将会被无限期地软锁。这是因为如果出现另一个读者,他们总是被优先考虑。对于 boost:shared_mutex,所有线程都会优先考虑 最终(1)读者和写者都不会挨饿。

这里的 tl; dr 是指,如果您有一个非常高吞吐量的系统,没有停机时间和非常高的争用,那么如果不在其上手动构建一个优先级系统,std::shared_mutex将永远无法为您工作。boost::shared_mutex将开箱即用,尽管在某些情况下可能需要对其进行修补。我认为 std::shared_mutex的行为是一个潜在的错误,在大多数使用它的代码中都会发生。

(1) < sub > 实际使用的算法基于 OS 线程调度器。根据我的经验,当读操作饱和时,Windows 上的暂停时间(获得写锁时)要比 OSX/Linux 上的长。