How to use values from a thread

Values cannot be returned from a thread; that can only be done in functions, as seen in the previous article. In functions, on the other hand, values can be returned, and they can also be passed by reference. If the argument is passed by reference, the result of the calculation is not returned. When a value is passed by reference, the called function modifies the value of the argument. That can also be done in a thread. It might not be the most recommended way of doing it, but it is a good starting point. The result from the calculation is stored in a private data member of the class. The object of that class can be used as if it were a function pointer. To pass your function object to the thread as a reference, you need to use std::ref(). If you do not do that, there will not be a result to retrieve. Make sure that the referenced object’s lifetime extends beyond the life of the thread. To see how it works, you can find a class Addition below.

Result from thread using reference

In the class Addition, there is a constructor that takes three integers as arguments, and there are a function object and a function. The function object does the calculation, and the function returnResult() returns the result in main. The object add is created, and the three values are initialized. The function object is then passed by reference to the thread using std::ref(). The result can only be retrieved when the thread has finished executing. The result is printed in the thread as well as in main.

#include <iostream>
#include <thread>
#include <print>
using namespace std;

class Addition
{
public:
	Addition(int nr_1, int nr_2, int nr_3) : in_nr_1(nr_1), in_nr_2(nr_2), in_nr_3(nr_3) {}
	void operator() () {
		answer = in_nr_1 + in_nr_2 + in_nr_3;
		println("The answer in the thread: {}", answer);
	}
	int returnResult() const { return answer; }

private:
	int in_nr_1{ 0 }, in_nr_2{ 0 }, in_nr_3{ 0 }, answer{ 0 };
};

int main()
{
	Addition add(5, 8, 7);
	thread t2{ ref(add) }; // Pass reference
	t2.join();
	println("The answer in main: {}", add.returnResult());
	println();
}

Promises and Futures

A better way of retrieving a value from a thread is to use promises. A promise is an object of the class std::promise. The object is the provider of the result in the thread. A promise is used to set an asynchronous result. The result can be retrieved, and the thread can continue to run. The promise must be associated with a future to be able to use the result in another thread or in main.

To give an example of how to use values calculated in threads, we need a class that can solve a problem. In this case, two numbers are multiplied. The standard classes promise and future are included in the standard library header <future>. It is a part of the thread support library.

Result from a thread using promises and futures

In the class Multiply, there is a constructor and a public function. The function is declared void. There is a promise and two integers declared private. There are three arguments in the constructor — two integers and a promise. A promise cannot be copied; it can only be moved into a thread.

#include <iostream>
#include <print>
#include <thread>
#include <future>
using namespace std;

class Multiply
{
public:
	Multiply(int nr_1, int nr_2, promise<int> prom_a)
		: in_nr_1{ nr_1 }, in_nr_2{ nr_2 }, prom_answer{ move(prom_a) }
	{
		println("Constructor for object passed into the thread.");
	}

	void numbers() {
		answer = in_nr_1 * in_nr_2;
		prom_answer.set_value(answer);
		println("The answer in the thread is: {}", answer);
	}

private:
	promise<int> prom_answer;
	int in_nr_1{ 0 }, in_nr_2{ 0 }, answer{ 0 };
};

int main()
{
	int a = 5, b = 20;
	promise<int> prom_answer;
	auto fut_answer{ prom_answer.get_future() };
	Multiply obj_Thread(a, b, move(prom_answer));
	thread t1{ &Multiply::numbers, &obj_Thread };
	t1.join();
	auto number = fut_answer.get();
	println("The answer in main is: {}", number);
}

In main, there are two integers, a and b, and a promise. The result is stored in the promise, and a future is used to get access to the result. The promise is created in main to pass to the thread. Then a future is created from the promise. The thread then calls get_future() to be able to access the result stored in the promise. In the next line, an object of the class Multiply is created, and the constructor is called. As pointed out earlier, the promise must be moved — it cannot be copied. That can be seen both in the constructor and in main. Both the function numbers() and the object must be passed to the thread function. Here, the thread t1 runs Multiply::numbers() on the object obj_Thread. A member function is passed as the function, and the object obj_Thread is supplied as the object pointer. In this case, std::ref() is not used, because the argument is not modified.


Above are two examples of how to retrieve results from threads. Both examples use object-oriented programming. The main question is still left to be answered: concurrency means that two or more threads run in parallel. There is more to learn to get there.

Next
Next

Concurrency in C++: Threads, Challenges, and Examples