2017-11-30 5 views
3

私が理解しているように、std :: asyncの通常の実装は、あらかじめ割り当てられたスレッドプールからのスレッドに対するこれらのジョブをスケジュールします。長時間実行可能なstd :: asyncは他のstd :: asyncを枯渇させることができますか?

だから、最初にスレッドプールを占有しているすべてのスレッドを占有するのに十分な長期実行型のメッセージを作成してスケジュールを設定しておきます(std::async)。その後すぐに(彼らの実行が終わるまで)、私は短時間実行してstd::asyncを作成してスケジュールします。長時間走っているものの少なくとも1つが終了するまで、短時間走っているものがまったく実行されないことが起こりうるか?あるいは、この種の状況を防ぐスタンダード(特にC++ 11)にいくつかの保証があります(OSがラウンドロビン方式でそれらをスケジューリングできるようにもっと多くのスレッドを生成するなど)?

+1

実装に依存します。あなたは、C + +の標準またはいくつかの特定の実装について尋ねていますか? –

+1

理想的には、標準からの保証が必要です。しかし、あなたにはそのような保証はないと言われているように、私は特にGCCのlibstdC++(GCC 5.4、それが重要である)の動作に興味があります。 – Dreamer

答えて

2

標準読み取り:

打ち上げ::非同期がポリシーに設定されている場合[futures.async#3.1]、コールINVOKE(DECAY_­COPY(std​::​forward<F>(f)), DECAY_­COPY(std​::​forward<Args>(args))...)([func.require]、[thread.thread.constr])であたかも非同期を呼び出したスレッドで評価されるDECAY_COPYへの呼び出しを持つスレッドオブジェクトによって表される新しい実行スレッド。 [...] async()​async起動ポリシーで呼び出されたとき

ので、として-IFのルールの下で、新しいスレッドが生み出されなければなりません。もちろん、インプリメンテーションはスレッドプールを内部的に使用することがありますが、通常のスレッド作成オーバヘッドは別として、特別な「飢え」は発生しません。さらに、スレッドローカルの初期化のようなものは常に起こるはずです。

実際には、打ち鳴らすのlibC++トランク非同期実装は読む:あなたが見ることができるよう

unique_ptr<__async_assoc_state<_Rp, _Fp>, __release_shared_count> 
     __h(new __async_assoc_state<_Rp, _Fp>(_VSTD::forward<_Fp>(__f))); 

VSTD::thread(&__async_assoc_state<_Rp, _Fp>::__execute, __h.get()).detach(); 

return future<_Rp>(__h.get()); 

、NO '明示的な' スレッド・プールは、内部的に使用されていません。

さらに、hereを読むことができるので、gcc 5.4.0で出荷されるlibstdC++の実装では、単なるスレッドが呼び出されます。

+1

ポリシーが 'launch :: async | launch :: deferred'(デフォルト)実装はどちらかを選択することができます – Caleth

+0

@Caleth、うん、私は起動::非同期呼び出しのみに関連する質問を仮定しました(そうでなければ、質問はほとんど意味がありません)。また、実装には起動ポリシーも用意されています... –

0

はい、MSVCのstd::asyncは、少なくともMSVC2015以降はそのプロパティを持つようです。

2017年のアップデートで修正したかどうかわかりません。

これは標準の精神に反します。しかし、この規格はスレッドの進捗状況の保証については非常に曖昧です(少なくともC++ 14では)。したがって、std::asyncstd::threadをラップするように動作する必要がありますが、std::threadフォワード進行の保証は十分に弱いため、as-ifルールでの保証はあまりありません。実際に

、これはその問題を持っているように見えていませんMSVC2015でstd::threadの生の使用など、std::threadに生のコールと私のスレッドプールの実装でstd::asyncを置き換えるために私をリードしてきました。

は、私が(タスクキュー付き)スレッドプールがstd::asyncまたはstd::threadのいずれかに生のコールよりもはるかに実用的であることがわかり、それがstd::threadまたはstd::asyncのいずれかでスレッドプールを書くことは本当に簡単ですと、私がお勧めしますstd::threadと書いてください。

スレッドプールは、std::asyncのように返すことができます(ただし、プール自体がスレッドの存続期間を管理するため、破壊機能の自動ブロッキングはありません)。

私は、C++ 17がより進歩的な進歩保証を追加したと読んだが、MSVCの動作が現在の標準要件に反していると結論づけるのに十分な理解がない。

+0

* "std :: thread forwardの進捗状況は十分に弱いため、as-ifルールの下での保証はあまりありません" *私はそうではありません確かにこれは確信している。標準の手紙は、非同期の観察可能な効果は新しい実行スレッドのものでなければならないと述べています。逆に、MSVC実装で実行されるプログラムは、async()呼び出しが等価なスレッド呼び出しとは異なる動作をするという証拠を収集することができます(これは*スレッド実行の保証が無意識に*発生します)。 –

+0

@MassimilianoJanes標準を除いて、 'std :: thread'が合理的に*動作することを保証するものではありません。 'std :: thread'が動作する標準保証とは動作が異なりません。抽象的なマシン動作以外の方法での動作のみが異なります。観察可能な振る舞いは、「この標準で義務付けられている抽象機械と振る舞いの観点から」という意味でなければならない。他のもの(スタックトレースを行う場合のようなもの)は明らかに同一ではありません。それが起こると、未定のフォワード進行保証は、 'std :: thread'が' async'と同じくらい悪くなる可能性があることを意味します。 – Yakk

+0

はい、 "thread(foo).detach(); bar();" * * as-ifルールの下で "thread(foo).join(); bar()として振る舞いますが、これらの2つのコードはas-ifルールと同等*であると結論できますか? –

関連する問題