C++: Simple return value from std::thread?

C++Multithreading

C++ Problem Overview


With win32 threads I have the straight forward GetExitCodeThread() that gives me the value which the thread function returned. I'm looking for something similar for std::thread (or boost threads)
As I understand this can be done with futures but how exactly?

C++ Solutions


Solution 1 - C++

See this video tutorial on C++11 futures.

Explicitly with threads and futures:

#include <thread>
#include <future>

void func(std::promise<int> && p) {
    p.set_value(1);
}

std::promise<int> p;
auto f = p.get_future();
std::thread t(&func, std::move(p));
t.join();
int i = f.get();

Or with std::async (higher-level wrapper for threads and futures):

#include <thread>
#include <future>
int func() { return 1; }
std::future<int> ret = std::async(&func);
int i = ret.get();

I can't comment whether it works on all platforms (it seems to work on Linux, but doesn't build for me on Mac OSX with GCC 4.6.1).

Solution 2 - C++

I'd say:

#include <thread>
#include <future>
 
int simplefunc(std::string a)
{ 
    return a.size();
}
 
int main()
{
      auto future = std::async(simplefunc, "hello world");
      int simple = future.get();
 
      return simple;
}

Note that async even propagates any exceptions thrown from the thread function

Solution 3 - C++

Using C++11 threads, one can't get the return value as thread exit which used to be the case with pthread_exit(...)

You need to use C++11 Future<> to get the return value. Future is created using templated argument where the template takes the return value (built in of User Defined types)..

You can fetch the value in another thread using future<..>::get(..) function.

one benefit of using future<..> is that you can check the validity of return value i.e if it's already taken, you avoid calling get() accidentally by checking the validity using future<..>::isValid(...) function.

Here is how you'll write the code.

#include <iostream>
#include <future>
using namespace std;
auto retFn() {
    return 100;
}
int main() {
    future<int> fp = async(launch::async, retFn);
    if(fp.valid())
       cout<<"Return value from async thread is => "<<fp.get()<<endl;
    return 0;
}

it should also be noted that we can get the future run on the same thread by using launch::deferred option as

 future<int> fp = async(launch::deferred, retFn);

Solution 4 - C++

I think a reference variable reads much more intuitively.

std::mutex m;

void threadFunction(int& val) {
    std::lock_guard<std::mutex> guard(m);
    val = 5;
}

int x = 0;
std::thread theThread(threadFunction, std::ref(x));
theThread.join();
std::cout << x << std::endl;
// prints 5

Solution 5 - C++

Pass a reference / pointer to the thread with std::ref

async is just better than this, but just for science, it can be done:

void myfunc_reference(int& i);
std::thread(myfunc_reference, std::ref(output));

I suspect that the implementation of async must be doing something along those lines under the hood for us, which is essentially what you have to do in the pthread backend: https://stackoverflow.com/questions/2251452/how-to-return-a-value-from-thread-in-c

You have to ensure of course that the variable lifetime lasts until the thread returns.

The following runnable code example compares async and this worse method:

main.cpp

#include <cassert>
#include <future>
#include <iostream>
#include <thread>
#include <vector>

int myfunc(int i) {
    return i + 1;
}

void myfunc_reference(int& i) {
    i = myfunc(i);
}

int main() {
    unsigned int nthreads = 4;
    std::vector<int> inputs{1, 2, 3, 4};
    std::vector<int> outputs_expect{2, 3, 4, 5};

    // future and sync. Nirvana. When you are not fighting to death with types:
    // https://stackoverflow.com/questions/10620300/can-stdasync-be-use-with-template-functions
    {
        std::vector<std::future<int>> futures(nthreads);
        std::vector<int> outputs(nthreads);
        for (decltype(futures)::size_type i = 0; i < nthreads; ++i) {
            futures[i] = std::async(
                myfunc,
                inputs[i]
            );
        }
        for (decltype(futures)::size_type i = 0; i < nthreads; ++i) {
            outputs[i] = futures[i].get();
        }
        assert(outputs_expect == outputs);
    }

    // Reference arguments.
    //
    // Annoying because requires:
    //
    // - wrapping the return function to accept references
    // - keeping an array of outputs
    // - std::ref
    {
        std::vector<std::thread> threads(nthreads);
        std::vector<int> inouts(inputs);
        for (decltype(threads)::size_type i = 0; i < nthreads; ++i) {
            threads[i] = std::thread(myfunc_reference, std::ref(inouts[i]));
        }
        for (auto& thread : threads) {
            thread.join();
        }
        assert(outputs_expect == inouts);
    }
}

GitHub upstream.

Compile and run with:

g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp -pthread
./main.out

Tested in Ubuntu 19.04.

Solution 6 - C++

Here is a more specific example.

A function simulates download with a callback parameter to show progress and to cancel the download.

namespace __HeavyWork
{
	int SimulateDownload(std::function<int(int)> dlCallBack)
	{
		for (size_t i = 0; i < 100; i++)
		{
			std::this_thread::sleep_for(std::chrono::seconds(1));

			if (dlCallBack(i) == -1)
			{
				return i;
			}
		}

		return 100;
	}
}

We want to get the download status,

#include <thread>
#include <future>

    void test()
	{
		auto simulateCancellation = []()->bool {
			static bool b = true;
			if (b)
			{
				srand((unsigned int)time(NULL));
				b = false;
			}
			return (rand() % 7) == 0;
		};

		auto funDLCallback = [&](int i)->int {
			if (simulateCancellation())
			{
				return -1;
			}
			cout << "download: " << i << endl;
			return i;
		};
		auto funDownload = [&](std::promise<int> && p) {
			p.set_value(__HeavyWork::SimulateDownload(funDLCallback));
		};



		std::promise<int> p;
		auto f = p.get_future();
		std::thread t(funDownload, std::move(p));
		//dlg.doModal();
		t.join();
		cout << "return value: " << f.get() << endl;
	}

Solution 7 - C++

You can create a set of threads using the code below with threads and futures:

#include <thread>
#include <future>

void func(promise<float> && prms) {

    prms.set_value(0.125);

}

in the main:

vector<pair<thread, future<float>>> threads;

for (int i = 0; i < std::thread::hardware_concurrency(); i++) {

                promise<float> prms;
                future<float> fut = prms.get_future();

                ///Triggering threads
                thread th(func, move(prms));
                ///Pushing thread and result to vector
                threads.push_back(make_pair(move(th), move(fut)));
          
        }
        cout<< "Killing threads ... \n";
        for (auto& e : threads)
        {
            auto th = move(e.first);
            auto fut = move(e.second);
            float flt = fut.get();
            //cout << flt << endl;
            th.detach();
        }

Solution 8 - C++

It all depends on your definition of "simple".

Using futures will certainly do the magic trick in a few lines of C++, but I find it debatable to hijack a mechanism that was designed for parallel processing for such a trivial use.

futures mostly make sense on multicore CPUS, where they allow a process to launch unsynchronized tasks that will leech computing power from the other cores (leaving aside the fact that finding a set of uncorelated data big enough to be worth the effort is not such a trivial matter either).

Using the whole mechanism as a workaround to retrieve a mere int return value is what I call syntax-driven software design. It sits pretty as a showcase for C++11 versatility, but it does hide considerable resource consumption under an icing of syntactic sugar.

If not for using other cores as raw power source, what is the point in creating a thread if you don't mean to communicate with it until it's done?
Because if you do, retrieving whatever status from it, be it at termination or anytime else, will be a trivial matter and you will not even think of using futures in the first place.

Except for the (arguable) convenience of it or the aesthetic appeal, what do these kinds of tricks achieve functionally that could be considered useful enough to offset the hidden costs?

Reading such answers with no proper multitasking background, the new kids on the block might be tempted by using these kind of inefficient mechanisms on a regular basis.
That would only pollute future software with more cases of Schlemiel the Painter's syndrom.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionshooshView Question on Stackoverflow
Solution 1 - C++Alex BView Answer on Stackoverflow
Solution 2 - C++seheView Answer on Stackoverflow
Solution 3 - C++Deepak Kr GuptaView Answer on Stackoverflow
Solution 4 - C++Martin GView Answer on Stackoverflow
Solution 5 - C++Ciro Santilli Путлер Капут 六四事View Answer on Stackoverflow
Solution 6 - C++ZhangView Answer on Stackoverflow
Solution 7 - C++Hamed HasibiView Answer on Stackoverflow
Solution 8 - C++kuroi nekoView Answer on Stackoverflow