The promise is the last synchronization mechanism. We already wrote about the others, namely std::async, std::packaged_task and std::condition_variable.

Similar as with other synchronization techniques, the promise is associated with a std::future. std::async and std::packaged_task set a value to the future by returning from a callable object. But the promise can explicitly set the value to the future. Let’s explain how this works.

Promise

We would like to set a value, of the type int, to the future.

Creation

First, the default constructor of the std::promise creates a promise.

std::promise<int> promise;

The promise has a template parameter int, because we would like to set a value of the type int to the future.

The future

The .get_future() member function of the std::promise creates a future.

std::future<int> future = promise.get_future();

The template parameter of the future is the same as the template parameter of the promise.

Setting the value

The .set_value(...) member function of the std::promise sets the value to the future.

promise.set_value(42);

We already know how to obtain the value from the future:

int answer = future.get();

In our example, the answer is 42, because the promise sets the value 42 to the future.

Typical usage

The typical usage of the promise is:

  • creating a promise,

  • retrieving the future from the promise,

  • passing the promise to some other thread,

  • setting a value to the future via the promise,

  • obtaining the value from the future.

Temperature tomorrow re-revisited

We will use the following, already well known, story:

A couple, wife and husband, are going on a picnic tomorrow. The wife would like to know what will be the temperature of the weather. Therefore, she asks her husband to look it up.

We modeled this story with the std::async and the std::packaged_task. But in this example, we will use the std::promise for the synchronization.

#include <iostream>
#include <string>
#include <chrono>

#include <thread>
#include <future>
#include <utility>


void make_break(int millisec)
{
    std::this_thread::sleep_for(std::chrono::milliseconds(millisec));
}

The beginning is the same as in previous examples: the include statements and make_break function.

void temperature(std::promise<int> answer)
{
    std::cout << "Husband: Hm, is the weather "
              << "forecast in the newspaper?\n" 
              << "         Eh, we don't "
              << "have a newspaper at home..." << std::endl;
    
    make_break(2);
    
    std::cout << "Husband: I will look it up on the internet!" << std::endl;
    
    make_break(2);
    
    std::cout << "Husband: Here it is, "
              << "it says tomorrow will be 40." << std::endl;
    
    answer.set_value(40);
}

The argument of the temperature(...) is the std::promise<int>. At the end, the function sets the value to the associated future via .set_value(...) member function of the promise.

int main()
{
    std::cout << "Wife:    Tomorrow, we are going on a picnic.\n" 
              << "         What will be the weather...\n" 
              << "         \"What will be the "
              << "temperature tomorrow?\"" << std::endl;
    
    std::promise<int> promise;
    std::future<int> answer = promise.get_future();
    std::thread thread(temperature, std::move(promise));
    thread.detach();
    
    make_break(2);
    
    std::cout << "Wife:    I should pack for tomorrow." << std::endl;
    
    make_break(2);

    std::cout << "Wife:    Hopefully my husband can figure out the weather soon."
              << std::endl;
    
    int temp = answer.get();

    std::cout << "Wife:    Finally, tomorrow will be " << temp << "... Em...\n"
              << "         \"In which units is the answer?\"" 
              << std::endl;

    return 0;
}

The main function creates a promise and retrieves the future from the promise. Then, we pass the promise to the temperature(...) function which is executed in another thread. The std::promise is not copyable, therefore std::move moves it to the function.

At the end, the .get() member function of the future retrieves the value.

The entire source code is available here. The output of the program is:

$ ./promise
Wife:    Tomorrow, we are going on a picnic.
         What will be the weather...
         "What will be the temperature tomorrow?"
Husband: Hm, is the weather forecast in the newspaper?
         Eh, we don't have a newspaper at home...
Wife:    I should pack for tomorrow.
Husband: I will look it up on the internet!
Wife:    Hopefully my husband can figure out the weather soon.
Husband: Here it is, it says tomorrow will be 40.
Wife:    Finally, tomorrow will be 40... Em...
         "In which units is the answer?"

This is the third solution of this problem. First one used std::async and second one used std::packaged_task. Now, we can compare the solutions between each other and see the semantic differences between them.

Summary

The std::promise can directly set a value to the associated std::future with .set_value() member function.

In this article, we learned how to use the std::promise.

Links: