14

を取得する 1 つの方法std::futureは、次のstd::asyncとおりです。

int foo()
{
  return 42;
}

...

std::future<int> x = std::async(foo);

この例では、xの非同期状態のストレージはどのように割り当てられ、どのスレッド (複数のスレッドが関与している場合) が割り当ての実行を担当していますか? さらに、クライアントはstd::async割り当てを制御できますか?

コンテキストについては、 のコンストラクターの 1 つがアロケーターを受け取る可能性があることがわかりますが、 のレベルでstd::promiseの割り当てをカスタマイズできるかどうかはわかりません。std::futurestd::async

4

2 に答える 2

8

メモリは を呼び出すスレッドによって割り当てられ、std::asyncそれがどのように行われるかを制御することはできません。通常、これは の何らかのバリアントによって実行されnew __internal_state_typeますが、保証はありません。malloc、または目的のために特別に選択されたアロケータを使用できます。

30.6.8p3 [futures.async] から:

launch::async | launch::deferred「効果: 最初の関数は、 のポリシー引数とと の同じ引数を持つ 2 番目の関数の呼び出しFと同じように動作しますArgs。2 番目の関数は、返された将来のオブジェクトに関連付けられた共有状態を作成します。...」

「最初の関数」は起動ポリシーのないオーバーロードであり、2 つ目は起動ポリシーのあるオーバーロードです。

の場合、std::launch::deferred他のスレッドは存在しないため、呼び出し元のスレッドですべてが発生する必要があります。の場合std::launch::async、30.6.8p3 は次のように続けます。

policy & launch::asyncがゼロでない場合 — を呼び出したスレッドで への呼び出しが評価されるINVOKE (DECAY_COPY (std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...)スレッド オブジェクトによって表される実行の新しいスレッドであるかのように (20.8.2, 30.3.1.2) を呼び出します...DECAY_COPY ()async

強調を追加しました。関数と引数のコピーは呼び出し元のスレッドで行われる必要があるため、これには基本的に、共有状態が呼び出し元のスレッドによって割り当てられる必要があります。

もちろん、新しいスレッドを開始し、それが状態を割り当てるのを待ってから、それfutureを参照する を返す実装を作成することもできますが、なぜそれを行うのでしょうか?

于 2012-10-11T08:01:53.343 に答える
7

の単なる引数から判断するstd::asyncと、内部の割り当てを制御する方法がないように思われるためstd::promise、おそらくstd::allocator. 理論的には未指定だと思いますが、呼び出しスレッド内で共有状態が割り当てられている可能性があります。この問題について、標準に明示的な情報は見つかりませんでした。最終的には、非同期呼び出しを簡単に行うための非常に特殊な機能であるため、実際どこかに があるstd::asyncかどうかを考える必要はありません。std::promise

非同期呼び出しの動作をより直接的に制御するにはstd::packaged_task、実際にアロケーター引数を持つ もあります。std::packaged_taskしかし、単なる標準的な引用からは、このアロケーターが関数のストレージを割り当てるために使用されるだけなのか (は特別な のようなものであるためstd::function)、それとも internal の共有状態を割り当てるためにも使用されるのかは完全には明らかではありませんstd::promise。 :

30.6.9.1 [先物.タスク.メンバー]:

効果:共有状態で新しいオブジェクトを構築しpackaged_task、オブジェクトのストアド タスクを で初期化しますstd::forward<F>(f)。引数を取るコンストラクターは、Allocatorそれを使用して、内部データ構造を格納するために必要なメモリを割り当てます。

まあ、それは下にあるとさえ言っていませんstd::promise(同様にstd::async)、それは単に a に接続可能な未定義の型である可能性がありstd::futureます。

したがって、 が内部共有状態をどのように割り当てるかが実際に指定されていない場合std::packaged_task、最善の策は、非同期関数呼び出し用の独自の機能を実装することです。std::packaged_task簡単に言えば、aは単に a にstd::functionバンドルされておりstd::promise、新しいスレッドで a をstd::async開始するだけであることを考えるとstd::packaged_task(そうでない場合を除いて)、これはあまり問題にはなりません。

しかし、実際には、これは仕様上の見落としである可能性があります。割り当て制御は実際には に適合しませんが、アロケーターstd::asyncの説明std::packaged_taskとその使用法は少し明確になるかもしれません。ただし、これは意図的なものでもある可能性があるため、は必要なものを自由に使用でき、内部std::packaged_taskで を必要とすることさえありません。std::promise

編集:もう一度読んでみると、上記の標準的な引用は、 「内部データ構造」std::packaged_taskの一部であるため、提供されたアロケーターを使用しての共有状態割り当てられると実際に言っていると思います。ただし、実際の である必要があります)。したがって、非同期タスクの共有状態を明示的に制御するには、これで十分だと思います。std::promisestd::packaged_taskstd::future

于 2012-10-11T08:04:06.753 に答える