boost::future 和 std::future 的不同行为

Different behavior of boost::future and std::future

具体来说,boost::future 似乎没有在析构函数中阻塞。还有 boost documentation didn't mention it. However std::future did mention 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 中 return 得到的 future 对象的析构函数似乎在 2017 年之后的某个时间点真的变成了非阻塞的,所以你 应该使用 .get() 阻止.


我不能阻止它因为:

  • BOOST_THREAD_FUTURE_BLOCKING(未记录)并非在所有情况下都是 #defined;
  • 如果你手动 #define BOOST_THREAD_FUTURE_BLOCKING,你可以看到当 future 被销毁时 ~future_async_shared_state_base() 将被调用 lambda 传递给async 已经完成 运行(即当 boost::shared_ptr 的 use_count 从 2 下降到 1 再到 0),所以未来对象的析构函数 return 从 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 被销毁时 传递给异步的 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.then 更复杂的情况下拆分控制流:CppCon 2015: Gor Nishanov “C++ Coroutines - a negative overhead abstraction"。您可以尝试像 cppcoro 或 boost.fiber 这样的库,并在复杂的控制结构中暂停任务函数(例如 co_await inside if inside while inside for)。

C++23 Executor TS:在 A Unified Executors Proposal for C++ 的初始版本中有 OneWayExecutor execute(即发即弃)TwoWayExecutor twoway_execute (return 一个未来)then_execute(取一个未来和一个函数,return 一个未来)等等,但在最近的版本中,它们被发送者和接收者所取代。