Using boost::future with continuations and boost::when_all - c++

I would like to use boost::future with continuations and boost::when_all / boost::when_any.
Boost trunk - not 1.55 - includes implementations for the latter (modeled after the proposal here, upcoming for C++14/17 and Boost 1.56).
This is what I have (and it does not compile):
#include <iostream>
#define BOOST_THREAD_PROVIDES_FUTURE
#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
#define BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY
#include <boost/thread/future.hpp>
using namespace boost;
int main() {
future<int> f1 = async([]() { return 1; });
future<int> f2 = async([]() { return 2; });
auto f3 = when_all(f1, f2);
f3.then([](decltype(f3)) {
std::cout << "done" << std::endl;
});
f3.get();
}
Clang 3.4 bails out with a this - here is an excerpt:
/usr/include/c++/v1/memory:1685:31: error: call to deleted constructor of 'boost::future<int>'
::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
Am I doing it wrong or is this a bug?

The problem is that when_all may only be called with rvalue future or shared_future. From N3857:
template <typename... T>
see below when_all(T&&... futures);
Requires: T is of type future<R> or shared_future<R>.
Thanks to the reference-collapsing rules, passing an lvalue results in T being deduced to future<T>& in violation of the stated requirement. The boost implementation doesn't check this precondition so you get an error deep in the template code where what should be a move of an rvalue future turns into an attempted copy of an lvalue future.
You need to either move the futures into the when_all parameters:
auto f3 = when_all(std::move(f1), std::move(f2));
or avoid naming them in the first place:
auto f = when_all(async([]{return 1;}),
async([]{return 2;}));
Also, you must get the future returned from then instead of the intermediate future:
auto done = f.then([](decltype(f)) {
std::cout << "done" << std::endl;
});
done.get();
since the future upon which you call then is moved into the parameter of the continuation. From the description of then in N3857:
Postcondition:
The future object is moved to the parameter of the continuation function
valid() == false on original future object immediately after it returns
Per 30.6.6 [futures.unique_future]/3:
The effect of calling any member function other than the destructor, the move-assignment operator, or valid on a future object for which valid() == false is undefined.
You could avoid most of these issues in c++14 by avoiding naming the futures at all:
when_all(
async([]{return 1;}),
async([]{return 2;})
).then([](auto&) {
std::cout << "done" << std::endl;
}).get();

Related

Is it still valid when the variable passed to `std::async` is out of scope?

Is the code snippet below legal? What worries me is when factorial is invoked the fut_num may be already out of scope.
#include <future>
#include <vector>
#include <iostream>
//int factorial(std::future<int> fut) //works, because there is a move constructor
int factorial(std::future<int>&& fut)
{
int res = 1;
int num = fut.get();
for(int i=num; i>1; i--)
{
res *= i;
}
return res;
}
int main()
{
std::promise<int> prs;
std::vector<std::future<int>> vec;
{
std::future<int> fut_num{prs.get_future()};
vec.push_back(std::async(std::launch::async, factorial, std::move(fut_num)));
} //`fut_num` is out of range now.
prs.set_value(5);
for(auto& fut: vec)
{
std::cout << fut.get() << std::endl;
}
}
And the same question about similar code snippet:
#include <future>
#include <vector>
#include <iostream>
//int factorial(std::future<int> fut) //works, because there is a move constructor
int factorial(std::future<int>& fut)
{
int res = 1;
int num = fut.get();
for(int i=num; i>1; i--)
{
res *= i;
}
return res;
}
int main()
{
std::promise<int> prs;
std::vector<std::future<int>> vec;
{
std::future<int> fut_num{prs.get_future()};
vec.push_back(std::async(std::launch::async, factorial, std::ref(fut_num)));
} //`fut_num` is out of range now.
prs.set_value(5);
for(auto& fut: vec)
{
std::cout << fut.get() << std::endl;
}
}
My two cents about these code snippets:
1.The former code snippet is legal, since std::async copies std::move(fut_num)(i.e. std::move(fut_num) is passed by value to std::async). So there is a local fut_num when fcatorical is called.
2.The latter one is illegal, since fut_num is passed as a reference to std::async. When fut_num is out of scope, it's illegal to call functions which uses fut_num.
The first one is fine, the second one is not.
std::async with std::launch::async uses the same procedure of invoking the thread function as the constructor of std::thread does. Both effectively execute
std::invoke(auto(std::forward<F>(f)), auto(std::forward<Args>(args))...);
in the new thread, but with the auto(...) constructions executing in the context of the calling thread.
Here F/Args... are the (other) template parameters with corresponding forwarding-reference function parameters F&& f/Args&&... args and auto has the new C++23 meaning which creates a prvalue/temporary of the decayed argument's type from the argument.
See [futures.async]/4.1.
This means there will be unnamed copies constructed for all arguments which live in the new thread until after the thread function invocation returns.
So with std::move(fut_num), there will actually be another std::future<int> object which will be move-constructed from fut_num and live until the thread ends execution. factorial will be passed a reference to this unnamed object.
With std::ref(fut_num) you are explicitly by-passing this mechanism protecting you from passing references to the objects in the constructing thread.
The constructor will still make a decayed copy of type std::reference_wrapper<std::future<int>> from the argument, but that object will just contain a reference referring to fut_num in the main thread.
std::invoke will then unwrap the std::reference_wrapper before passing to factorial and the fut argument will refer to fut_num in the main thread, which is then destroyed without any synchronization, causing undefined behavior as it is also accessed in the factorial function.
It either case it doesn't matter whether factorial takes the argument by-reference or by-value. Nothing about the above reasoning changes.

Pass by reference to a function accepting a universal reference

I am trying to use an API which sets a value of a variable based on an HTTP call. The function in which I can set the variable which will be set upon an HTTP Call is of type T&&. I would like to access this variable on a different thread. I tried to simplify the problem and represent it in the following code, as two threads, accessing a variable the same way.
#include <iostream>
#include <thread>
#include <chrono>
class Values
{
public:
int i;
std::string s;
};
template<typename T>
void WriteCycle(T&& i)
{
using namespace std::chrono_literals;
while (true)
{
i++;
std::cout << i << std::endl;
std::this_thread::sleep_for(500ms);
}
}
template<typename T>
void ReadCycle(T&& i)
{
using namespace std::chrono_literals;
while (true)
{
std::cout << i << std::endl;
std::this_thread::sleep_for(500ms);
}
}
int main() {
auto v = new Values();
std::thread t1(WriteCycle<int>, v->i);
std::thread t2(ReadCycle<int>, v->i);
t1.join();
t2.join();
}
Currently the read thread does not see any change in the variable. I read up an perfect forwarding, move semnatics and forwardin references, but I did not get it (I mostly program dotnet, my c++ knowledge is pre C++11). I tried all combinations of std::move, std::ref and std::forward but I cannot get the read thread to see the change of the write thread. Is there a way to solve this, without changing the T&& input type of the functions (since that is part of the API I am trying to use)? How to solve this in a thread-safe way?
Such notation:
template<typename T>
void WriteCycle(T&& i)
Doesn't really mean an rvalue reference, it means a universal reference, which could be an lvalue reference or rvalue reference depending on what kind of data you pass.
In your case it turns into just an lvalue reference, so it has nothing to do with move semantic. The problem is that thread constructor is not quite friendly with references and you may want just to use std::ref to get it round:
auto myRef = std::ref(v->i);
std::thread t1(WriteCycle<&int>, myRef);
std::thread t2(ReadCycle<&int>, myRef);
However it still won't be perfect, because you want to synchronize between threads with use of mutexes or atomic values

What is the difference between std::invocable and std::regular_invocable concepts?

What is the difference between std::invocable and std::regular_invocable? Based on the description from
https://en.cppreference.com/w/cpp/concepts/invocable I would expect that the std::regular_invocable concept doesn't allow to change the state of of the function object when it is called (or at least the result of the calling should always return the same result).
Why the code below compiles?
Compiled with a command: g++-10 -std=c++2a ./main.cc.
#include <iostream>
#include <concepts>
using namespace std;
template<std::regular_invocable F>
auto call_with_regular_invocable_constraint(F& f){
return f();
}
template<std::invocable F>
auto call_with_invocable_constraint(F& f){
return f();
}
class adds_one {
int state{0};
public:
int operator()() {
state++;
return state;
}
};
int main()
{
auto immutable_function_object([]() { return 1; });
adds_one mutable_function_object;
// I would expect only first three will be compiled and the last one will fail to compile because the procedure is
// not regular (that is does not result in equal outputs given equal inputs).
cout << call_with_invocable_constraint(immutable_function_object) << endl;
cout << call_with_invocable_constraint(mutable_function_object) << endl;
cout << call_with_regular_invocable_constraint(immutable_function_object) << endl;
cout << call_with_regular_invocable_constraint(mutable_function_object) << endl; // Compiles!
}
Output of the program:
1
1
1
2
From the reference:
Notes
The distinction between invocable and regular_invocable is purely semantic.
This means that there is no way for the compiler to enforce the distinction through the concepts system, since that can only check syntactic properties.
From the introduction to the concepts library:
In general, only the syntactic requirements can be checked by the compiler. If the validity or meaning of a program depends whether a sequenced of template arguments models a concept, and the concept is satisfied but not modeled, or if a semantic requirement is not met at the point of use, the program is ill-formed, no diagnostic required.
Hypothetically, we could write:
template< class F, class... Args >
concept regular_invocable = invocable<F, Args...> &&
requires(F&& f, Args&&... args) {
auto prev = f;
std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
assert(f == prev);
// TODO assert that `args` are unchanged
// TODO assert that invoking `f` a second time gives the same result
};
However, this would not actually test that the assertion holds, since a requires clause is not invoked at run time but only checked at compile time.
regular_invocable tells the user of the function that it will assume, that the result calling that regular_invocable function with the same value of the arguments will result in the same return value, and might cache that result due to that.
Caching the result could either be done by the function that expects regular_invocable or the compiler could use that information to optimize away multiple function calls to the regular_invocable function when the value of the arguments stay the same. So right now it can be seen as documentation and compiler hint.
Similar to const_cast it might not always be possible for the compiler to check if it is valid. Due to that and because there is currently not attribute/keyword in the standard to mark a function to always return the same value, there is right now no way to enforce at compile time that the function passed regular_invocable really matches that requirement.

Is there any way to extend the lifetime of a temporary object in C++?

I wrote a scope guard which resets a value when the scope exits:
template <class T>
struct ResetGuard
{
T old_value;
T& obj_to_reset;
ResetGuard(T& obj_to_reset, const T& new_value) :
old_value(obj_to_reset),
obj_to_reset(obj_to_reset)
{
obj_to_reset = new_value;
}
~ResetGuard() { obj_to_reset = old_value; }
};
When this scope guard is returned from a function, is there any way to prevent the immediate destruction of the scope guard if it wasn't saved?
For example:
int GLOBAL_VALUE = 0;
ResetGuard<int> temporarily_set_global_value(int new_val) {
return { GLOBAL_VALUE, new_val }; //updates the global variable
}
void foo() {
//Ideally, someone calling this function
//Wouldn't have to save the returned value to a local variable
temporarily_set_global_value(15);
std::cout << "GLOBAL_VALUE is " << GLOBAL_VALUE << std::endl;
}
The way it's written now, anyone calling one of the functions would have to remember to always save the ResetGuard to a local variable, otherwise it would immediately reset the value.
Some context around what I'm trying to do
I'm writing a library to format and manipulate strings. I have one global variable controlling how floating point numbers are formatted. I know that global variables are typically a terrible idea, but please bear with me.
I made the decision to use a global variable carefully. The alternative to using a global variable would be to pass around the object containing the formatting specification. This option ultimately proved infeasible: my library is designed to work with any objects that provide a implicit conversion to std::string. There's no way to pass formatting options (or any parameters, really) to an implicit conversion function. Hence, I had to resort to using a global variable.
Before answering your question, I like to provide the correct way of solving this problem in C++.
template <class T>
struct [[nodiscard]] ResetGuard
{
T old_value;
T& obj_to_reset;
bool enabled{true};
ResetGuard(T& obj_to_reset, const T& new_value) :
old_value(obj_to_reset),
obj_to_reset(obj_to_reset)
{
obj_to_reset = new_value;
}
ResetGuard(ResetGuard &&rhs)
: old_value(rhs.old_value)
, obj_to_reset(obj_to_reset)
{
rhs.enabled = false;
}
~ResetGuard()
{
if (enabled)
obj_to_reset = old_value;
}
ResetGuard(const ResetGuard &) = delete;
ResetGuard &operator=(const ResetGuard &) = delete;
ResetGuard &operator=(ResetGuard &&) = delete;
};
void foo() {
auto guard = temporarily_set_global_value(15);
std::cout << "GLOBAL_VALUE is " << GLOBAL_VALUE << std::endl;
}
The above code contains several interesting elements:
[[nodiscard]] prevent creating temporaries without creating a variable to ensure scope
The member enabled: Prevent the Dtor of a temporary to have a side effect
Move constructor: The move constructor allows moving the ResetGuard into a different scope with the right handling. In this case, disabling the old ResetGuard
As an extra note, I like to point attention to a C++17 extension (previously allowed optimization), which is called Guaranteed Copy/Move Elision. This will ensure that in practice no extra temporary instances will exist.
Back to your question: Is there any way to extend the lifetime of a temporary object in C++?
Yes, thanks to N0345 (Proposal from 1993). This proposal allows extension of a temporary by capturing it by const reference.
const auto &guard = temporarily_set_global_value(15);
However, it is unclear to me how many instances you will have in total. However, if you use the solution with the move constructor, this is no longer an issue. Further more, when you use compiler optimizations, this function could be inlined when implemented in the header. That could eliminate all copies.
Is there any way to extend the lifetime of a temporary object in C++?
Only one way, assign it to a variable (possibly a reference). If you don't want to burden users of the library, you can hide the details behind a macro. While it's true that the uses of macros become few and far between, this is something you can only do with a macro. For instance, here's how you'd do it with a sprinkle of GCC extensions:
#define CONCAT(a, b) a##b
#define SCOPED_GLOBAL_VALUE(x) \
auto&& CONCAT(_unused, __COUNTER__) __attribute__((unused)) = temporarily_set_global_value(x)
So now when users write:
SCOPED_GLOBAL_VALUE(15);
They get the variable, free of charge, with the expressiveness you wanted.
But of course, there's a caveat. Since we generate the variable name using the pre-processor, we can't use this macro in an inline function. If we do, we'll violate the one definition rule. So that's a thing to consider.
Personally, I wouldn't stress over this. It's a common idiom to require named RAII object (think lock_guard), so just being presented a properly named function would be straight forward for any savvy C++ programmer.
Sorry about my previous answer folks, what was I thinking? I should have read the question properly.
So, of course, foo() has to return your ResetGuard object in order to extend its lifetime, and this is a good thing, not a bad thing.
Firstly, it's hardly a burden on the caller. After all, all he / she has to do is:
auto rg = foo ();
As a potential caller of foo() I would have absolutely no problem with that, and #melpomene's excellent suggestion in the comments above ([[nodiscard]]) can be used to ensure that callers don't forget to do this.
And why is forcing the caller to do this a good thing (apart from the fact that you have no choice in the matter anyway)? Well, it gives the caller the opportunity to manage the lifetime of the scopeguard and that might be useful (will provide live demo soon).
As for the other answers here, I would most definitely not hide all this in a macro because that hides an important piece of information from potential callers of foo(). Instead, I would use [[nodiscard]] to remind them of their responsibilities and leave it at that.
[Edit]
I have now spent a little time over at Wandbox polishing up the code to add the full set of recommended constructors / assignment operators and to demonstrate the use of [[nodiscard]], which for me is the find of the day.
First, the modified class, done in the way (I believe) those who know are recommending. I can particularly see the importance of defining a proper move constructor (just think of the subtle bugs you might run into if you don't). Pinched some stuff (= delete) from JVApen, looks wise to me, TU JV.
#include <iostream>
#include <assert.h>
#define INCLUDE_COPY_MOVE_SWAP_STUFF
template <class T> class [[nodiscard]] ResetGuard
{
public:
ResetGuard (T& obj_to_reset, const T& new_value) : old_value (obj_to_reset), obj_to_reset (obj_to_reset)
{
obj_to_reset = new_value;
}
#ifdef INCLUDE_COPY_MOVE_SWAP_STUFF
ResetGuard (const ResetGuard& copy_from) = delete;
ResetGuard &operator= (const ResetGuard& copy_assign_from) = delete;
ResetGuard &operator= (ResetGuard&& move_assign_from) = delete;
ResetGuard (ResetGuard&& move_from) : old_value (move_from.old_value), obj_to_reset (move_from.obj_to_reset)
{
assert (!move_from.defunct);
move_from.defunct = true;
}
#endif
~ResetGuard()
{
if (!defunct)
obj_to_reset = old_value;
}
private:
T old_value;
T& obj_to_reset;
bool defunct = false;
};
Comment out #define INCLUDE_COPY_MOVE_SWAP_STUFF to see the compiler warning you get if you don't do all the things you're supposed to.
Test program:
int GLOBAL_VALUE = 0;
ResetGuard<int> temporarily_set_global_value (int new_val)
{
return { GLOBAL_VALUE, new_val }; // updates GLOBAL_VALUE
}
void bad_foo()
{
temporarily_set_global_value (15);
std::cout << "GLOBAL_VALUE in bad_foo () is " << GLOBAL_VALUE << std::endl;
}
void good_foo()
{
auto rg = temporarily_set_global_value (15);
std::cout << "GLOBAL_VALUE in good_foo () is " << GLOBAL_VALUE << std::endl;
}
auto better_foo()
{
auto rg = temporarily_set_global_value (15);
std::cout << "GLOBAL_VALUE in better_foo () is " << GLOBAL_VALUE << std::endl;
return rg;
}
int main ()
{
bad_foo ();
good_foo ();
std::cout << "GLOBAL_VALUE after good_foo () returns is " << GLOBAL_VALUE << std::endl;
{
auto rg = better_foo ();
std::cout << "GLOBAL_VALUE after better_foo () returns is " << GLOBAL_VALUE << std::endl;
{
auto rg_moved = std::move (rg);
std::cout << "GLOBAL_VALUE after ResetGuard moved is " << GLOBAL_VALUE << std::endl;
}
std::cout << "GLOBAL_VALUE after ResetGuard moved to goes out of scope is " << GLOBAL_VALUE << std::endl;
GLOBAL_VALUE = 42;
}
std::cout << "GLOBAL_VALUE after ResetGuard moved from goes out of scope is " << GLOBAL_VALUE << std::endl;
}
Compiler output:
prog.cc: In function 'void bad_foo()':
prog.cc:47:38: warning: ignoring returned value of type 'ResetGuard<int>', declared with attribute nodiscard [-Wunused-result]
temporarily_set_global_value (15);
^
prog.cc:40:17: note: in call to 'ResetGuard<int> temporarily_set_global_value(int)', declared here
ResetGuard<int> temporarily_set_global_value (int new_val)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
prog.cc:6:40: note: 'ResetGuard<int>' declared here
template <class T> class [[nodiscard]] ResetGuard
^~~~~~~~~~
Program output:
GLOBAL_VALUE in bad_foo () is 0
GLOBAL_VALUE in good_foo () is 15
GLOBAL_VALUE after good_foo () returns is 0
GLOBAL_VALUE in better_foo () is 15
GLOBAL_VALUE after better_foo () returns is 15
GLOBAL_VALUE after ResetGuard moved is 15
GLOBAL_VALUE after ResetGuard moved to goes out of scope is 0
GLOBAL_VALUE after ResetGuard moved from goes out of scope is 42
So there you have it. If you do all the things you're supposed to do (and I hope I have!) then everything works just fine, and it's all nice and efficient thanks to RVO and guaranteed copy elision so there's no need to worry about that either.
Live demo.

Race in std::future::unwrap() and std::future::get()

A followup with reference to the upcoming feature in C++20 from n3721 "Improvements to std::future and related APIs"
#include <iostream>
#include <future>
#include <exception>
using std::cout;
using std::endl;
int main() {
auto prom_one = std::promise<std::future<int>>{};
auto fut_one = prom_one.get_future();
std::thread{[prom_one = std::move(prom_one)]() mutable {
auto prom_two = std::promise<int>{};
auto fut_two = prom_two.get_future();
prom_two.set_value(1);
prom_one.set_value(std::move(fut_two));
}}.detach();
auto inner_fut_unwrap = fut_one.unwrap();
auto inner_fut_get = fut_one.get();
auto th_one = std::thread{[&]() {
cout << inner_fut_unwrap.get() << endl;
}};
auto th_two = std::thread{[&]() {
cout << inner_fut_get.get() < endl;
}};
th_one.join();
th_two.join();
return 0;
}
In the code above, which will win the race to print 1? th_one or th_two?
To clarify what race I was talking about, there are two (potential) racy situations here, the latter being the one that is really confusing me.
The first is in the setting and unwrapping of the inner future; the unwrapped future should act as a suitable proxy for the inner future even when the actual set_value has not been called on the inner future. So unwrap() must return a proxy that exposes a thread safe interface regardless of what happens on the other side.
The other situation is what happens to a get() from a future when a proxy for it already exists elsewhere, in this example inner_fut_unwrap is the proxy for inner_fut_get. In such a situation, which should win the race? The unwrapped future or the future fetched via a call to get() on the outer future?
This code makes me worried that there is some kind of misunderstanding about what futures and promises are, and what .get() does. It's also a bit weird that we have using namespace std; followed by a lot of std::.
Let's break it down. Here's the important part:
#include <iostream>
#include <future>
int main() {
auto prom_one = std::promise<std::future<int>>{};
auto fut_one = prom_one.get_future();
auto inner_fut_unwrap = fut_one.unwrap();
auto inner_fut_get = fut_one.get();
// Boom! throws std::future_error()
So neither thread "wins" the race, since neither thread actually gets a chance to run. Note from the document you linked, for .unwrap(), on p13:
Removes the outer-most future and returns a proxy to the inner future.
So the outer-most future, fut_one, is not valid. When you call .get(), it throws std::future_error1. There is no race.
1: Not guaranteed. Technically undefined behavior.