繁体   English   中英

用c ++ 11等价替换boost :: thread和boost :: mutex是否明智?

[英]Is it smart to replace boost::thread and boost::mutex with c++11 equivalents?

动机:我之所以考虑是因为我的天才项目经理认为提升是另一种依赖,而且它很可怕,因为“你依赖它”(我试着解释提升的质量,然后放弃一段时间后:(我想做的更小的原因是我想学习c ++ 11的功能,因为人们会开始在其中编写代码。所以:

  1. #include<thread> #include<mutex>和boost等价物之间是否存在1:1映射?
  2. 你会考虑用c ++ 11替换boost东西吗?
    东西。 我的用法是原始的,但有什么例子,当std没有提供什么提升? 或者(亵渎)反之亦然?

PS我使用GCC所以标题就在那里。

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_future vs std::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线程库中也存在一个错误,它阻止了这个工作,因为它在实现中也使用了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线程库的大部分完整实现-std=c++0x模式)。

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

std::thread主要在boost::thread之后建模,但有一些区别

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

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

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

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

如果您使用静态链接,由于这些gcc错误/功能, std::thread变得无法使用:

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

企业案例

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

基础/技术创业案例

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

我的经验

我个人偏爱硬化,使用频繁,高度兼容,高度一致的库,例如boost与非常现代的替代品。 对于诸如线程之类的复杂编程主题尤其如此。 另外,我在很多环境,编译器,线程模型等中使用boost::thread (以及一般的boost)取得了巨大的成功。当我选择它时,我选择了boost。

使用Visual Studio 2013时, std::mutex行为似乎与boost::mutex不同,这导致了一些问题(请参阅此问题 )。

关于在C ++ 17中添加的std :: shared_mutex

这里的其他答案提供了一般的差异的非常好的概述。 但是, std::shared_mutex有几个问题可以提升解决方案。

  1. 可升级的突变。 这些在std::thread中不存在。 它们允许读者升级为作家, 而不允许任何其他作者进入你之前 这些允许您在读取模式下执行诸如预处理大型计算(例如,重新索引数据结构)之类的操作,然后升级到写入以应用重新索引,同时仅在短时间内保持写入锁定。

  2. 公平。 如果您使用std::shared_mutex进行持续读取活动,则您的编写器将无限期地进行软锁定。 这是因为如果另一位读者出现,他们将始终优先考虑。 使用boost:shared_mutex ,所有线程最终都将获得优先权。 (1)读者和作家都不会被饿死。

tl; dr是如果你有一个非常高吞吐量的系统,没有停机时间和非常高的争用, std::shared_mutex将永远不会为你工作,如果没有手动建立一个优先系统。 boost::shared_mutex可以开箱即用,但在某些情况下你可能需要修改它。 我认为std::shared_mutex的行为是在大多数使用它的代码中等待发生的潜在错误。

(1) 它使用实际算法基于OS线程调度程序。 根据我的经验,当读取饱和时,Windows上的暂停(获取写锁定时)比OSX / Linux上的暂停时间长。

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

Boost还有更多功能。 例如,std版本中的头文件不向流提供序列化程序(即cout << duration)。 Boost有许多库使用自己的等价物,但不与std版本合作。

总结一下 - 如果你已经有一个使用boost编写的应用程序,那么保持你的代码是更安全的,而不是花些钱去转向C ++ 11标准。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM