使用c ++ 11线程返回结果的正确方法是什么?

时间:2013-09-13 04:43:04

标签: c++ multithreading c++11

如果我想从一个线程获得结果,以下哪个代码是正确的?或者有更好的方法来实现同一目标?

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;
}

3 个答案:

答案 0 :(得分:2)

有很多方法。

请参阅http://en.cppreference.com/w/cpp/thread/future

底部的示例代码

答案 1 :(得分:2)

在C ++ 11中,您想使用std::future

来自this documentation link

  

类模板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';
}

答案 2 :(得分:1)

第二个更简单,更好,更安全。

使用第一个,您将在两个线程之间共享一个对象bar。您显然需要强制执行某种形式的同步或策略,以便安全地使用结果对象。

第一个问题的另一个问题是引用的结果对象的生命周期与原始对象的生命周期有关,在您的情况下,它位于启动线程中。如果引用的对象超出范围而工作线程仍未完成其工作,并且仍未写入结果对象,则这可能非常不安全。

第二个问题要好得多,因为它解决了上述两个问题。您也可以在任何返回其结果的函数上使用它,而不知道它是否正在同时执行。当然,在共享数据时,您仍需要注意不要引入数据争用和未定义的行为,尤其是对于全局变量。


老实说,我认为你的第二个例子有点做作。您通常不希望在执行这样一个简单的任务时使用单独的线程。通过这种方式,您将自己暴露在数据竞争中。即使您同步访问它们,启动线程和同步的开销也会使它对单线程代码处于严重劣势。