Sharing Thread result by Promise and Future

Introduction

In this blog, Thread and Process in C++ – My sky (freewindcode.com), I mentioned that an operation on a thread could return results and have it captured by another thread. In this post, I will explain the concept and how to do that.

Concepts

Promise: class template provides a facility to store a value or an exception that is later acquired asynchronously via a std::future object. The future object must be associated with a the promise via promise::get_future() function.

  • The promise is created in caller thread.
  • The promise should be passed as reference to a function that the called thread runs.
  • The promise acquires the values of the thread operation from inside the function that the called thread runs. The promise uses set_value to the data.

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

  • Futures can use get function to get the result or exception that was set in the promise.
  • Futures stay in the calling thread.

The relationship between the {Caller, future} and {Called, promise} is illustrated as below:

Simply speaking: a future is one end of a communications channel through which a callee transmits a result to a caller.

Implementation

Getting future via associated promise

The following steps are to be done:

  1. Create a promise object
  2. Create and associate a future with the promise.
  3. Create a thread object, pass a function to be done the thread to its constructor. Pass the promise as the reference argument to the function.
    • Note that the function returns result. The result must be set_value in the promise.
  4. terminate thread
  5. get the result in the calling thread.
#include <iostream>
#include <thread>
#include <future>

int main()
{
    // 1. Create a promise object
    std::promise<int> p;
    // 2. Associate a future with the promise
    std::future<int> ft = p.get_future();

    // 3. Start a sub-thread, pass the promise to the thread's operation
    // and set return result to promise 
    std::thread t([&p]() {
        std::cout << "ThreadID: " << std::this_thread::get_id() << std::endl;
        p.set_value(5); // Set a value in the promise
    });

    // 4. Block main thread, wail till sub-thread finishes. 
    t.join();
    
    // 5. Main thread gets the result via future
    int result = ft.get();
    std::cout << "result " << result << std::endl;

    return 0;
}

Note that the above program uses lamda function where the promise is captured. We could also define a function where promise is passed in as a reference; then we invoke the thread.

void doSomething(std::promise<int> &p;
// in main:
std::thread t(doSomething, ref(p));

Getting future from a task-based thread operation

It is advisable to implement task-based programming.

With the task-based approach, the future returned from std::async offers the std::fucture::get function. The get function is even more important if thread operation emits an exception, get provides access to that, too. [1]

The following program uses std::async to run an anonymous function that returns 5. The std::assync will run the function in async mode and directly returns the future object.

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

int main()
{
    std::future<int> ft = std::async(std::launch::async, []{ return 5;})

    int result = ft.get(); 
    std::cout << "result " << result << std::endl;

    return 0;
}

Reference:

[1] Effective Modern C++. Item 35.

Leave a Reply

Your email address will not be published. Required fields are marked *