9

重複の可能性:
C++: std::thread からの単純な戻り値?

std::thread から戻りコードを取得する方法はありますか? 整数を返す関数があり、スレッドの実行が完了したときに関数からリターン コードを取得できるようにしたいと考えています。

4

4 に答える 4

19

いいえ、そのstd::threadためではありません。

代わりに、次asyncを取得するために使用しますfuture

#include <future>

int myfun(double, char, bool);

auto f = std::async(myfun, arg1, arg2, arg3);  // f is a std::future<int>

// ...

int res = f.get();

結果の準備ができているかどうかを確認するには、(ゼロ タイムアウトで)のwait_forメンバー関数を使用できます。f

于 2012-09-07T14:28:04.930 に答える
15

他の人が示唆しているように、施設は<future>これに使用できます。しかし、私は答えに反対します

いいえ、あなたはこれを行うことはできませんstd::thread

でやりたいことを行う 1 つの方法を次に示しますstd::thread。それは決して唯一の方法ではありません:

#include <thread>
#include <iostream>

int func(int x)
{
    return x+1;
}

int main()
{
    int i;
    std::thread t([&] {i = func(2);});
    t.join();
    std::cout << i << '\n';
}

これにより、移植可能な出力が得られます。

3
于 2012-09-07T15:33:01.560 に答える
14

Kerrek SBは彼の答えは正しいですが、私は別の例を追加することを提案しました(彼が提案したのは答えであるはずなので、ここにあります)。

最近、少なくともVC11ではstd::async、アプリケーションが終了するまでスレッドのすべてのリソースが解放されないことを発見しました。これにより、メモリリークの誤検知が発生する可能性があります(たとえば、Visual Leak Detectorを使用してそれらを監視している場合)。

ここで、ほとんどの基本的なアプリケーションでは、この回答の残りの部分を見る価値はありませんが、私のようにメモリリークをチェックする必要があり、最後に解放されない静的データのように、誤検知を発生させる余裕がないことを意味します主な機能。それがあなたの場合なら、これは役立つかもしれません。

std::asyncデフォルトでは、別のスレッドで実行されることが保証されていませんstd::launch::async。これは、最初のパラメーターとして使用する場合のみです。それ以外の場合、実装は何をするかを決定します。そのため、VC11実装は、新しいMicrosoft Concurrency Runtimeタスクマネージャーを使用して、提供された関数をタスクプールにプッシュされたタスクとして管理します。つまり、スレッドは透過的な方法で維持および管理されます。タスクマネージャーを明示的に終了する方法はありますが、プラットフォーム固有であるため、1)スレッドを起動し、2)後で結果を取得し、3)スレッドが完全に解放されたときに、非同期を選択するのは適切ではありません。結果が得られます


それを正確に行う代替手段は、を使用std::packaged_taskstd::threadて組み合わせることstd::futureです。それが行われる方法は、を使用するのとほとんど同じですがstd::async、もう少し冗長です(つまり、必要に応じてカスタムテンプレート関数で一般化できます)。

#include <packaged_task>
#include <thread>

int myfun(double, char, bool);

std::packaged_task<int(double, char, bool)> task(myfun, arg1, arg2, arg3); 

auto f = task.get_future();  // f is a std::future<int> 

std::promiseまず、タスクを作成します。基本的には、関数と将来に関連付けられる関数の両方を含むオブジェクトです。std::packaged_taskほとんどの場合、拡張バージョンのように機能しstd::functionます。

次に、スレッドを明示的に実行する必要があります。

std::thread thread(std::move(task));

thread.detach();

std::packaged_taskコピーできないため、移動が必要です。スレッドの切り離しは、futureを使用して同期する場合にのみ必要です。それ以外の場合は、スレッドを明示的に結合する必要があります。そうしないと、スレッドのデストラクタが呼び出されたときに、が呼び出されますstd::terminate()

// ...

int res = f.get(); // Synchronization and retrieval.
于 2012-09-07T15:22:29.033 に答える
3

を使用した例を次に示しpackaged_taskます。

#include <future>
#include <iostream>

void task_waiter(std::future<int>&& f) {
    std::future<int> ft = std::move(f);
    int result = ft.get();
    std::cout << result << '\n';
}

int the_task() {
    return 17;
}

int main() {
    std::packaged_task<int()> task(the_task);
    std::thread thr(task_waiter, task.get_future());
    task();
    thr.join();
    return 0;
}
于 2012-09-07T15:15:23.687 に答える