c++ - boost::future 和 std::future 的不同行为

标签 c++ boost

具体来说,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_awaitifwhilefor )。

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/

相关文章:

c++ - EVP_DigestUpdate 和 "invalid conversion from ‘unsigned char*’ 到 ‘const char*’"

c++ - 使用姐妹继承

python - 在 Mac OS X 上使用 bjam (Boost.Build) 构建 Python 扩展

C++ boost/property_tree/ini_parser.hpp : No such file or directory

C++ shared_ptr 保存动态分配的数组

c++ - boost::shared_mutex vs boost::mutex 用于多线程写入?

c++ - 如何找出对 C++ 符号的引用

c++ - 调试来自同一代码库的运行时差异

c++ - C++编译器如何解析虚函数访问非虚数据成员

c++ - 使用迭代器从 boost 多索引中删除项目时的一致性