[threads] Launch deferred for async
Hello all, I am using boost::async() to create futures from tasks in order to wrap some behavior that may or may not be sync. This behavior is implemented behind an interface and can be small and fast operations or longer running and blocking things. All return a future as a result type, so I can hide the ugly truth. For the smaller stuff I'd like to use launch::deferred to avoid threading altogether and just execute the task when the user get()s the future. boost::future<bool> ret = boost::async(boost::launch::deferred, [this] () -> bool { // do some small cpu only impl return result; }); But when i get the result: const bool result = ret.get(); ...the application crashes. Debugging this I came to this in boost/thread/future.hpp:9373 } else if (underlying_cast<int>(policy) & int(launch::deferred)) { std::terminate(); //BOOST_THREAD_FUTURE<R> ret; //return ::boost::move(ret); // return boost::detail::make_future_deferred_shared_state<Rp>( // BF( // thread_detail::decay_copy(boost::forward<F>(f)) // ) // ); } else { To me this sounds like the application will always std::terminate() when launch::deferred is chosen. Why is that? When I use launch::any it seems to work but why is there a parameter that always yields unwanted results. What is the reason behind it? Can I get launch::deferred as it is described (not threading, just executing the task sync when get() is called) somehow? Platform is x64 Windows 10, MSVC14.1. Cheers, Stephan
On 27/11/2018 02:30, Stephan Menzel wrote:
But when i get the result:
const bool result = ret.get();
...the application crashes. Debugging this I came to this in boost/thread/future.hpp:9373
} else if (underlying_cast<int>(policy) & int(launch::deferred)) { std::terminate(); //BOOST_THREAD_FUTURE<R> ret; //return ::boost::move(ret); // return boost::detail::make_future_deferred_shared_state<Rp>( // BF( // thread_detail::decay_copy(boost::forward<F>(f)) // ) // ); } else {
To me this sounds like the application will always std::terminate() when launch::deferred is chosen. Why is that?
This implementation appears to be conditioned on BOOST_THREAD_PROVIDES_VARIADIC_THREAD -- it's implemented "properly" when that is defined. In order to get that defined, you must be using at least a C++11 conformant compiler (and compilation mode) and have explicitly defined the following in all translation units that use Boost.Thread (prior to including it): #define BOOST_THREAD_VERSION 4 (or the equivalent project / command line option). This also makes Boost.Thread behave a more like std::thread, which might have other consequences if you were relying on the previous behaviour. I couldn't find any documentation that explains why this was left unimplemented for the non-variadic version; presumably there was some kind of compilation issue, or just an assumption that using new facilities requires using the latest interface version.
Hello Gavin, On Tue, Nov 27, 2018 at 4:06 AM Gavin Lambert via Boost < boost@lists.boost.org> wrote:
To me this sounds like the application will always std::terminate() when launch::deferred is chosen. Why is that?
This implementation appears to be conditioned on BOOST_THREAD_PROVIDES_VARIADIC_THREAD -- it's implemented "properly" when that is defined.
In order to get that defined, you must be using at least a C++11
conformant compiler (and compilation mode) and have explicitly defined the following in all translation units that use Boost.Thread (prior to including it):
#define BOOST_THREAD_VERSION 4
Ah, this explains it. I have BOOST_THREAD_VERSION 3 explicitly defined because I couldn't be having with some of the version 4 behavior. Which is why I prefer boost threads over std threads in the first place. Thanks for the heads up. I will try to re-evaluate if I should go for version 4 after all but as I recall there were some strong reasons not to do it. At least now I know what I'm trading in for that. Cheers, Stephan
On Tue, Nov 27, 2018 at 7:24 AM Stephan Menzel
Ah, this explains it. I have BOOST_THREAD_VERSION 3 explicitly defined because I couldn't be having with some of the version 4 behavior. Which is why I prefer boost threads over std threads in the first place.
Thanks for the heads up. I will try to re-evaluate if I should go for version 4 after all but as I recall there were some strong reasons not to do it. At least now I know what I'm trading in for that.
A little update in case anyone is interested. First of all, going to version 4 does indeed fix the problem. As to the reasons why I went to version 3 I have some curious findings. 1) When using version 4, boost::future<> doesn't exist. I have to use boost::unique_future<> instead, which is nowhere mentioned in the docs. So essentially, when I do the examples in the docs, I have to force the version to 3 or lower or it won't compile. Unless I use shared_future that is. 2) I have several occurrences of using boost::static_visitor for treating variants. And I often move the value into there. Like this: boost::apply_visitor(my_visitor, std::move(value)); Being seemingly unrelated to boost threads, this won't compile anymore when I remove threads version 3. I had to remove the std::move() operator. I have no idea why but the error novel suggests it's got something to do with boost units being somewhere in the include path. I do use boost units but nowhere near that apply visitor lines. I can live with both of these things but they appear very strange to me. Cheers, Stephan
On 27/11/2018 23:25, Stephan Menzel wrote:
Ah, this explains it. I have BOOST_THREAD_VERSION 3 explicitly defined because I couldn't be having with some of the version 4 behavior. Which is why I prefer boost threads over std threads in the first place.
Thanks for the heads up. I will try to re-evaluate if I should go for version 4 after all but as I recall there were some strong reasons not to do it. At least now I know what I'm trading in for that.
Sometimes you can enable specific sub-features of a new version while mostly using the old version, but combinations are probably less well tested and I would assume there are probably hidden dependencies.
1) When using version 4, boost::future<> doesn't exist. I have to use boost::unique_future<> instead, which is nowhere mentioned in the docs. So essentially, when I do the examples in the docs, I have to force the version to 3 or lower or it won't compile. Unless I use shared_future that is.
It should be the other way around -- version 2 (the default) uses unique_future<> while version 3 and 4 use future<>. https://www.boost.org/doc/libs/1_68_0/doc/html/thread/build.html#thread.buil... It was renamed due to alignment with the C++11 standard. Alias templates would have been nice, but I guess Boost.Thread is mostly targeted at C++03 and those aren't available there anyway.
2) I have several occurrences of using boost::static_visitor for treating variants. And I often move the value into there. Like this:
boost::apply_visitor(my_visitor, std::move(value));
I don't think I can help with that one, at least not without more context. :) Maybe the rest of the info on that page might help, since it appears you missed it?
participants (2)
-
Gavin Lambert
-
Stephan Menzel