lostyzd
lostyzd

Reputation: 4523

What is the correct way to return result by using c++11 thread?

If I want to get the result from a thread, which of the following code is correct? Or there exists better way to achieve the same goal?

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

And another case,

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

Upvotes: 2

Views: 225

Answers (3)

Mark Garcia
Mark Garcia

Reputation: 17708

The second one is simpler, better and safer.

With the first one, you are sharing an object, bar, between the two threads. You clearly need to enforce some form of synchronization or policy in order to safely use the result object.

Another issue with the first one is that the lifetime of the referenced result object is tied to the lifetime of the original object which, in your case, is in the initiating thread. This might be very unsafe if the referred-to object leaves out of scope with the worker thread still unfinished doing its job, and has still not written to the result object.

The second one is much better as it address the two issues above. You can also use it on any function that returns its result without that function knowing it is being concurrently executed. Of course you still need be careful not to introduce data races and undefined behavior when sharing data, especially with global variables.


To be honest, I think your second example is a bit contrived. You typically don't want to use separate threads in doing such a trivial task. With that, you are exposing yourself into a data race. Even if you do synchronize their access, the overhead of initiating a thread and synchronization would put it at a serious disadvantage against single threaded code.

Upvotes: 1

Prashant Kumar
Prashant Kumar

Reputation: 22519

In C++11, you want to use std::future

From this documentation link:

The class template std::future provides a mechanism to access the result of asynchronous operations

And some sample code, also from that link, to illustrate its use.

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

Upvotes: 2

Nicolas Louis Guillemot
Nicolas Louis Guillemot

Reputation: 1628

There are many ways.

See the example code at the bottom of http://en.cppreference.com/w/cpp/thread/future

Upvotes: 2

Related Questions