具体来说,boost::future
似乎没有在析构函数中阻塞。和boost documentation没有提到。然而 std::future 确实提到了 it .
如果我想将一些 .then()
链接到 boost::future
我还需要链接 .get()
调用最后强制临时对象阻塞以获得正确的行为。这是正确的使用方法吗?
void a()
{
boost::async([] {
boost::this_thread::sleep_for(boost::chrono::seconds{1});
std::cout << "Finished sleeping\n";
return 1;
});
std::cout << "End of a()\n";
}
void b()
{
std::async([] {
std::this_thread::sleep_for(std::chrono::seconds{1});
std::cout << "Finished sleeping\n";
return 1;
});
std::cout << "End of b()\n";
}
int main()
{
a();//No finished sleeping printed
std::cout << "End of main()\n";
}
int main()
{
b();//finished sleeping will print
std::cout << "End of main()\n";
}
最佳答案
https://www.boost.org/doc/libs/1_75_0/doc/html/thread/synchronization.html
The returned futures behave as the ones returned from boost::async, the destructor of the future object returned from then will block. This could be subject to change in future versions.
(2015) https://www.boost.org/doc/libs/1_75_0/doc/html/thread/changes.html
Version 4.5.0 - boost 1.58
Fixed Bugs:
#10968 The futures returned by async() and future::then() are not blocking.
(2017)https://github.com/boostorg/thread/issues/194
I'm aware of the issue. Boost.thread did it by design following std::async and the first proposals of std::future::then.
The problem is that changing the behavior (even if it is not desired in some contexts) would be a breaking change. I would need to crate a new version, but Idon't want to create a new version using compiler flags as this has become a nightmare to maintain.
So I will need to create a boost/thread_v5 which will produce different binaries lib_boost_thread_v5.a. Boost.Threads is not structured this way, and this will mean a lot of work.
This is the single way to avoid breaking changes, but before doing that I would like to enumerate all the breaking changes that should be on this new version.
似乎是从 async
返回的 future 对象的析构函数在 2017 年之后的某个时间点确实已更改为非阻塞,因此您应该使用 .get()
阻止。
我无法阻止它,因为:
-
BOOST_THREAD_FUTURE_BLOCKING
(未记录)不是#define
d 在所有情况下; - 如果你
#define BOOST_THREAD_FUTURE_BLOCKING
手动,你可以看到~future_async_shared_state_base()
当future
时将被调用被销毁并且传递给 async 的 lambda 已完成运行(即,当boost::shared_ptr
的 use_count 从 2 下降到 1 再到 0 时),因此 future 对象的析构函数从async
返回(当boost::shared_ptr
的 use_count 从 2 下降到 1 时)仍然不会阻塞。
https://www.boost.org/doc/libs/1_75_0/boost/thread/detail/config.hpp
#if BOOST_THREAD_VERSION>=5
//#define BOOST_THREAD_FUTURE_BLOCKING
#if ! defined BOOST_THREAD_PROVIDES_EXECUTORS \
&& ! defined BOOST_THREAD_DONT_PROVIDE_EXECUTORS
#define BOOST_THREAD_PROVIDES_EXECUTORS
#endif
#else
//#define BOOST_THREAD_FUTURE_BLOCKING
#define BOOST_THREAD_ASYNC_FUTURE_WAITS
#endif
https://www.boost.org/doc/libs/1_75_0/boost/thread/future.hpp
在async
:
void init(BOOST_THREAD_FWD_REF(Fp) f)
{
#ifdef BOOST_THREAD_FUTURE_BLOCKING
this->thr_ = boost::thread(&future_async_shared_state::run, static_shared_from_this(this), boost::forward<Fp>(f));
#else
boost::thread(&future_async_shared_state::run, static_shared_from_this(this), boost::forward<Fp>(f)).detach();
#endif
}
当 future
被销毁并且传递给 async 的 lambda 已完成运行:
~future_async_shared_state_base()
{
#ifdef BOOST_THREAD_FUTURE_BLOCKING
join();
#elif defined BOOST_THREAD_ASYNC_FUTURE_WAITS
unique_lock<boost::mutex> lk(this->mutex);
this->waiters.wait(lk, boost::bind(&shared_state_base::is_done, boost::ref(*this)));
#endif
}
C++20 已转向协程,它能够在比 future 更复杂的情况下分割控制流。那么:CppCon 2015: Gor Nishanov “C++ Coroutines - a negative overhead abstraction" 。您可以尝试像 cppcoro 或 boost. Fiber 这样的库,并暂停复杂控制结构内的任务函数(例如 co_await
内 if
内 while
内 for
)。
C++23 执行器 TS:在 A Unified Executors Proposal for C++ 的初始版本中有OneWayExecutor
execute
(一劳永逸)TwoWayExecutor
twoway_execute
(返回一个 future )then_execute
(接受一个 future 和一个函数,返回一个 future)等,但在最近的版本中,它们被发送者和接收者取代。
关于c++ - boost::future 和 std::future 的不同行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65907870/