2

スレッドから結果を取得したい場合、次のコードのうち正しいものはどれですか? または、同じ目標を達成するためのより良い方法はありますか?

void foo(int &result) {
  result = 123;
}

int bar() {
  return 123;
}

int main() {
  int foo_result;
  std::thread t1(foo, std::ref(foo_result));
  t1.join();

  std::future<int> t2 = std::async(bar);
  int bar_result = t2.get();
}

そして別のケース、

void baz(int beg, int end, vector<int> &a) {
  for (int idx = beg; idx != end; ++idx) a[idx] = idx;
}

int main() {
  vector<int> a(30);
  thread t0(baz, 0, 10, ref(a));
  thread t1(baz, 10, 20, ref(a));
  thread t2(baz, 20, 30, ref(a));

  t0.join();
  t1.join();
  t2.join();

  for (auto x : a) cout << x << endl;
}
4

3 に答える 3

2

多くの方法があります。

http://en.cppreference.com/w/cpp/thread/futureの下部にあるサンプル コードを参照してください。

于 2013-09-13T04:44:38.653 に答える
2

C++11 では、使用したいstd::future

このドキュメント リンクから:

クラス テンプレート std::future は、非同期操作の結果にアクセスするメカニズムを提供します。

また、その使用法を説明するための、そのリンクからのサンプルコード。

#include <iostream>
#include <future>
#include <thread>

int main()
{
    // future from a packaged_task
    std::packaged_task<int()> task([](){ return 7; }); // wrap the function
    std::future<int> f1 = task.get_future();  // get a future
    std::thread(std::move(task)).detach(); // launch on a thread

    // future from an async()
    std::future<int> f2 = std::async(std::launch::async, [](){ return 8; });

    // future from a promise
    std::promise<int> p;
    std::future<int> f3 = p.get_future();
    std::thread( [](std::promise<int>& p){ p.set_value(9); }, 
                 std::ref(p) ).detach();

    std::cout << "Waiting..." << std::flush;
    f1.wait();
    f2.wait();
    f3.wait();
    std::cout << "Done!\nResults are: "
              << f1.get() << ' ' << f2.get() << ' ' << f3.get() << '\n';
}
于 2013-09-13T04:54:41.397 に答える
1

2 番目の方法は、よりシンプルで、より優れており、より安全です。

最初のものでは、オブジェクト をbar2 つのスレッド間で共有しています。結果オブジェクトを安全に使用するには、何らかの形式の同期またはポリシーを適用する必要があることは明らかです。

最初の問題のもう 1 つの問題は、参照された結果オブジェクトの有効期間が、元のオブジェクトの有効期間に関連付けられていることです。この場合、元のオブジェクトは開始スレッドにあります。これは、参照先のオブジェクトがスコープ外に出て、ワーカー スレッドがまだ仕事を終えておらず、結果オブジェクトにまだ書き込まれていない場合、非常に安全ではない可能性があります。

2 番目の方法は、上記の 2 つの問題に対処するため、はるかに優れています。また、その関数が同時に実行されていることを知らなくても、結果を返す任意の関数で使用できます。もちろん、特にグローバル変数を使用してデータを共有する場合は、データ競合や未定義の動作が発生しないように注意する必要があります。


正直なところ、あなたの2番目の例は少し不自然だと思います。通常、このような簡単なタスクを実行する際に別のスレッドを使用することは望ましくありません。それで、あなたはデータ競争に身をさらしています。それらのアクセスを同期したとしても、スレッドと同期を開始するオーバーヘッドにより、シングル スレッド コードに対して重大な不利な点になります。

于 2013-09-13T04:51:39.557 に答える