When I run the following code,
#include <future>
int main()
{
std::promise<int> p;
p.set_value(1);
return 0;
}
std::system_error
is thrown. However, when I set the promise's value in another thread,
#include <future>
#include <thread>
int main()
{
std::promise<int> p;
std::thread([&]{p.set_value(1);}).join();
return 0;
}
everything works fine. From what I understand about std::promise
, calling set_value
shouldn't throw an exception unless the promise has no shared state (i.e. it's been moved from) or a value has already been assigned to it, and even then it would throw std::future_error
, not std::system_error
. Since there's no data race or anything of that sort, it shouldn't matter whether I call set_value
from the thread in which I created the promise or in another thread. Is there something I'm missing?
I've tried this using both g++ and clang with the same results. Specifically, when I run the code at the top, the following is output to stderr:
terminate called after throwing an instance of 'std::system_error'
what(): Unknown error -1
Aborted (core dumped)
These commands were used to compile the code at the top,
g++ main_thread.cpp -o main_thread -std=c++17 -g -Og
clang main_thread.cpp -o main_thread -std=c++17 -lstdc++
and these were used to compile the code at the bottom:
g++ separate_thread.cpp -o separate_thread -lpthread -std=c++17 -g -Og
clang separate_thread.cpp -o separate_thread -std=c++17 -lstdc++ -lpthread
Although the purpose of std::future and std::promise is to pass objects between threads. However, std::future objects cannot be manipulated by multiple threads at the same time.
In case of an error, the promise becomes rejected, and the execution should jump to the closest rejection handler. But there is none. So the error gets “stuck”. There’s no code to handle it.
Normally, such .catch doesn’t trigger at all. But if any of the promises above rejects (a network problem or invalid json or whatever), then it would catch it. The code of a promise executor and promise handlers has an "invisible try..catch " around it. If an exception happens, it gets caught and treated as a rejection.
.catch handles errors in promises of all kinds: be it a reject () call, or an error thrown in a handler. We should place .catch exactly in places where we want to handle errors and know how to handle them. The handler should analyze errors (custom error classes help) and rethrow unknown ones (maybe they are programming mistakes).
std::promise
is part of the Thread Support Library so it would stand to reason that it requires enabling thread support in your compiler options (e.g. -pthread
).
Note that -pthread
affects the compilation as well as linkage stages. From man g++
:
-pthread
Adds support for multithreading with the pthreads library. This option sets flags for both the preprocessor and linker.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With