std::promise is a c++ class that provides a facility to store a value or an exception to be asynchronously acquired laterly via std::future object created by std::promise object.
std::promise makes cross-thread exception possible.
std::promise object can be referenced to or std::move to sub-thread.
#include <iostream>
#include <future>
#include <thread>
#include <complex> // std::sqrt
#include <functional>
#include <vector>
using std::string_literals::operator""s;
namespace nsa
{
std::mutex mutex;
class my_class
{
private:
void make_value(std::promise<double> & promise, int value)
{
std::this_thread::sleep_for(std::chrono::seconds(2));
if (value < 0)
throw std::runtime_error{"Negative value is not allowed: "s + std::to_string(value)};
promise.set_value(std::sqrt(value));
}
private:
void run_value(std::promise<double> & promise, int value)
{
try
{
this->make_value(std::ref(promise), value);
}
catch (...)
{
std::exception_ptr ptr = std::current_exception();
promise.set_exception(ptr);
}
}
private:
void be_back(std::promise<double> && promise, int value)
{
this->print("Be back: I will be back.");
this->run_value(std::ref(promise), value);
}
void i_will(std::promise<double> & promise, int value)
{
this->print("I will: I will be back.");
this->run_value(std::ref(promise), value);
}
public:
void back_set(int value)
{
std::promise<double> promise;
std::future<double> future = promise.get_future();
std::jthread thread{
std::bind(
&nsa::my_class::be_back,
this,
std::placeholders::_1,
std::placeholders::_2
),
std::move(promise),
value
};
thread.detach();
this->print("back_set: wait ...");
std::this_thread::sleep_for(std::chrono::seconds(1));
this->print("back_set: get ...");
double r = future.get();
this->print("back_set: get value: "s + std::to_string(r));
}
void i_set(int value)
{
std::promise<double> promise;
std::future<double> future = promise.get_future();
std::jthread thread{
std::bind(
&nsa::my_class::i_will,
this,
std::placeholders::_1,
std::placeholders::_2
),
std::ref(promise),
value
};
thread.detach();
this->print("i_set: wait ...");
std::this_thread::sleep_for(std::chrono::seconds(1));
this->print("i_set: get ...");
double r = future.get();
this->print("i_set: get value: "s + std::to_string(r));
}
private:
void back_wrap(int value)
{
try
{
this->back_set(value);
}
catch (const std::exception & e)
{
this->print("back_wrap c++ std::exception: "s + e.what());
}
}
void i_wrap(int value)
{
try
{
this->i_set(value);
}
catch (const std::exception & e)
{
this->print("i_wrap c++ std::exception: "s + e.what());
}
}
public:
void run()
{
std::vector<std::jthread> pool;
for (int i=-3; i<=3; ++i)
{
pool.emplace_back(
std::bind(
&nsa::my_class::back_wrap,
this,
std::placeholders::_1
),
i
);
}
for (int i=-3; i<=3; ++i)
{
pool.emplace_back(
std::bind(
&nsa::my_class::i_wrap,
this,
std::placeholders::_1
),
i
);
}
}
public:
void print(const std::string & str) const
{
std::unique_lock<std::mutex> lock{nsa::mutex};
std::cout << str << std::endl;
}
};
}
int main()
{
nsa::my_class object;
object.run();
}
Jul 6, 2025