boost :: threadとboost :: mutexを同等のc ++ 11に置き換えるのは賢明ですか?


153

動機:私が検討している理由は、私の天才プロジェクトマネージャーが、ブーストは別の依存関係であり、「あなたはそれに依存している」ために恐ろしいと思っているためです(ブーストの品質について説明しようとしましたが、しばらくしてから断念しました:( )。私がそれをしたい小さな理由は、人々がコードを書き始めるので、私はc ++ 11の機能を学びたいということです。

  1. #include<thread> #include<mutex>同等のものの間で1:1のマッピングがありますか?
  2. boostのものをc ++ 11の
    ものに置き換えることをお勧めしますか?私の使用法は原始的ですが、stdが何を後押しするのか提供しない例はありますか?または(冒とく)その逆ですか?

PS私はGCCを使用しているため、ヘッダーがあります。


46
IMO Googleコーディングガイドラインは多くの点で愚かです...たとえば。彼らはC ++ 11からの自動を許可しません... :)
NoSenseEtAl

5
引用のガイドライン:[自動]は、読みやすさを妨げます(タイプ名など)のチェックされた冗長性(タイプ名など)が読みやすくなる可能性があります。
アンドリュー・トマゾス2012年

31
for(auto it = v.begin()... :)
NoSenseEtAl

15
@ AndrewTomazos-Fathomling:本当に?個人的には、イテレータの実際のタイプ(おそらく数回)を気にしたことはないと思います。サポートされている演算のみです...構文の冗長性はめったにないと思います(DRY)。
Grizzly、

16
btw googleはそのダムのガイドラインを変更したので、最終的に自動を許可します
NoSenseEtAl 2013年

回答:


192

Boost.ThreadとC ++ 11標準スレッドライブラリにはいくつかの違いがあります。

  • Boostはスレッドのキャンセルをサポートしていますが、C ++ 11スレッドはサポートしていません
  • C ++ 11はをサポートしていますstd::asyncが、Boostはサポートしていません
  • Boostには、boost::shared_mutex複数のリーダー/単一のライターのロックがあります。類似のものstd::shared_timed_mutexはC ++ 14(N3891std::shared_mutex以降でのみ利用可能ですが、C ++ 17(N4508)以降でのみ利用可能です。
  • C ++ 11タイムアウトは、Boostタイムアウトとは異なります(ただし、Boost.Chronoが受け入れられたため、すぐに変更されるはずです)。
  • 名前の一部が異なります(例:boost::unique_futurevs std::future
  • の引数渡しのセマンティクスstd::threadは異なりますboost::thread--- Boostはboost::bind、コピー可能な引数を必要とするを使用します。std::threadなどの移動のみのタイプstd::unique_ptrを引数として渡すことができます。の使用によりboost::bind_1ネストされたバインド式などのプレースホルダーのセマンティクスも異なる場合があります。
  • 明示的に呼び出さない場合、join()またはデストラクタと割り当て演算子は、破棄/割り当て先のスレッドオブジェクトを呼び出します。C ++ 11 オブジェクトを使用すると、アプリケーションが呼び出され、アプリケーションが異常終了します。detach()boost::threaddetach()std::threadstd::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)));

ブーストを使用している場合、コンパイラがサポートしていれば、おそらく比較的簡単にC ++ 11スレッドに切り替えることができます(たとえば、Linux上のGCCの最近のバージョンには、-std=c++0xモードで使用できるC ++ 11スレッドライブラリのほぼ完全な実装があります)。

コンパイラがC ++ 11スレッドをサポートしていない場合、Just :: Threadなどのサードパーティの実装を取得できる可能性がありますが、これは依然として依存関係です。


1
(読者や作家のための個別のロック/アンロックの方法がありますlock/ unlock読者のための「lock_shared / unlock_shared」対作家のために)。ライターが使用していない限り、複数のリーダーがブロックせずにlock_sharedを呼び出すことができます。
Dave S

2
shared_mutexドキュメントがであるboost.org/doc/libs/1_47_0/doc/html/thread/...。mutexを共有または排他としてロックしてから、対応するロック解除関数を使用します。RAIIタイプを使用してこれを行うこともできます(shared_lock共有読み取りロックlock_guardunique_lock取得し、排他ロックを取得します)。私は移動のみのタイプについての要点を明確にしようとしました。
アンソニーウィリアムズ

3
私をつまずかせたもう1つのマイナーなこと:boostでは、実行中のスレッドのデストラクタがそれを切り離し(boost.org/doc/libs/1_47_0/doc/html/thread/…)、C ++では、実行中のスレッド呼び出しのデストラクタが終了する()(FDIS 30.3.1.3)
Cubbi

3
C ++ 11では、try_scoped_lock機能はでカバーされていstd::unique_lockます。mutexとを取り、std::try_to_lockその後try_lock()ではなくmutexを呼び出すコンストラクターがありlock()ます。stdthread.co.uk/doc/headers/mutex/unique_lock/…を
アンソニーウィリアムズ

4
はい、Boost.Threadは、私がこれを書いて以来、主にVicente Botetの働きにより、C ++ 11標準に非常に近くなっています。
アンソニーウィリアムズ

24

std::threadは主にをモデルにboost::threadしていますが、いくつかの違いがあります。

  • boostのコピー不可、1ハンドルマップから1 osスレッドまでのセマンティクスは保持されます。ただし、このスレッドは移動可能で、ファクトリー関数からスレッドを返し、コンテナーに配置できます。
  • この提案は、キャンセルをに追加しますがboost::thread、これは非常に複雑です。この変更は、スレッドだけでなく、C ++スレッドライブラリの残りにも大きな影響を与えます。この大きな変化は利益のために正当化できると信じられています。
    • スレッドデストラクタは、親スレッドがキャンセルされたときに子スレッドを誤ってリークしないように、デタッチする前にキャンセルを呼び出す必要があります。
    • キャンセルせずにデタッチを有効にするには、明示的なデタッチメンバーが必要になりました。
  • スレッドハンドルとスレッドIDの概念は2つのクラスに分かれています(これらはの同じクラスですboost::thread)。これは、スレッドIDのより簡単な操作と保存をサポートするためです。
  • 他の結合可能なスレッドと同等であることが保証されているスレッドIDを作成する機能が追加されました(boost::threadこれはありません)。これは、前の呼び出しと同じスレッドによって実行されているかどうかを知りたいコードに便利です(再帰的mutexは具体例です)。
  • クライアントが必要に応じて基盤となるOSを使用してスレッドを操作できるように、ネイティブスレッドハンドルを取得するための「バックドア」が存在します。

これは2007年からではありませんので、いくつかのポイントは、もはや有効です。boost::thread持っているnative_handle今の機能を、そして、コメンターが指摘するように、std::threadもうキャンセルはありません。

との間に大きな違いはboost::mutexありませんでしたstd::mutex


2
std::threadキャンセルはありません。それはboost::threadそうです!
アンソニーウィリアムズ

@Anthonyはinterrupt()、boost :: threadを意味していないと確信していますか?また、2007
Alex B

4
はい、ブーストのキャンセルは「中断」と呼ばれます。はい、これは古い提案です。C ++ 11標準(スレッドライブラリを含む)の最新の公開草案は、open-std.org / jtc1 / sc22 / wg21 / docs / papers / 2011 / n3242.pdf
Anthony Williamsの

6

に移行しない理由は1つありstd::threadます。

静的リンクを使用している場合std::thread、これらのgccバグ/機能のために使用できなくなります。

つまり、呼び出すstd::thread::detachstd::thread::join、例外またはクラッシュにつながるboost::thread場合は、これらの場合は問題なく動作します。


1つのバグは未確認で、もう1つは無効であることがわかりました。コメントには、記者がリンクすべきだったと書かれていますlibpthread.a。あなたが言っていることに本当に確信がありますか?
アインポクルム2015

1
@einpoklum、を使用して機能させることができるはずです。Wl,--whole-archive -lpthread -Wl,--no-whole-archive:stackoverflow.com/a/23504509/72178を参照してください。しかし、それをリンクするのは非常に簡単な方法ではなく、libpthread.a悪い考えと見なされます。
ks1322 2015

4
これは2016年なので、これらのバグが修正されたと想定できますか?バグは2012年に投稿され、gcc 4.9.2以降はC ++ 11を正式にサポートしているため、正式なサポートの前にC ++ 11に文句を言うことはできません。
スプラッシュ

6

エンタープライズケース

中程度から多種多様なオペレーティングシステムで実行する必要があり、その結果、それらのオペレーティングシステムでさまざまなコンパイラーとコンパイラーバージョン(特に比較的古いバージョン)を使用してビルドする必要がある企業向けのソフトウェアを作成している場合、私の提案は、とりあえず、C ++ 11全体。つまりstd::thread、は使用できません。を使用することをお勧めしboost::threadます。

ベーシック/テックスタートアップケース

1つまたは2つのオペレーティングシステム用に作成している場合、C ++ 11をほとんどサポートする最新のコンパイラ(例:VS2015、GCC 5.3、Xcode 7)でビルドする必要があるだけで、ブーストライブラリに依存しているstd::threadので、良いオプションかもしれません。

私の経験

私は個人的に、強化され、頻繁に使用され、互換性が高く、一貫性のあるライブラリ(boost対非常に最新の代替ライブラリなど)に不満があります。これは特に、スレッド化などの複雑なプログラミングの対象に当てはまります。また、私は長いboost::thread間、さまざまな環境、コンパイラー、スレッド化モデルなどで大きな成功を収めてきました(そして一般的にブーストもしました)。私が選択したとき、ブーストを選択します。


1
@UmNyobe彼は正しいです。C ++ 11スレッドの多くの実装はあまりにも壊れているので、人々がそれを使用することさえ考えていることに驚いています。
StaceyGirl


1

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のスレッドスケジューラに基づいています。私の経験では、読み取りが飽和すると、OSX / LinuxよりもWindowsの方が(書き込みロックを取得するときに)一時停止が長くなります。


0

boostの代わりにstdからshared_ptrを使用しようとしましたが、実際にこのクラスのgcc実装にバグが見つかりました。デストラクタが2回呼び出されたため、アプリケーションがクラッシュしました(このクラスはスレッドセーフであり、このような問題を生成しないはずです)。boost :: shared_ptrに移動すると、すべての問題が解消されました。C ++ 11の現在の実装はまだ成熟していません。

Boostにはさらに多くの機能があります。たとえば、stdバージョンのヘッダーは、ストリームにシリアライザーを提供しません(つまり、cout << duration)。Boostには、独自の同等のものなどを使用するライブラリが多数ありますが、stdバージョンとは連携しません。

まとめると、すでにboostを使用して記述されたアプリケーションがある場合は、C ++ 11標準への移行に少し労力を費やすよりも、コードをそのままにしておく方が安全です。


4
shared_ptrデストラクタは、一つのスレッド別のスレッドがそれを破壊している間に、オブジェクトへのアクセスを持っている未定義の動作ですが、スレッドセーフである必要はありません。GCCのshared_ptrにバグを見つけたと思われる場合は報告してください。そうでない場合は、間違って使用している可能性があります。
Jonathan Wakely
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.