我可以分离内部std :: future线程吗?

时间:2016-01-08 23:08:53

标签: c++ c++11

请考虑以下代码:

template <typename func_t, typename ... Args>
auto waiter (func_t func, const Args &... args) -> decltype(func(args...)) {
  const static std::chrono::milliseconds max_time(10);
  auto task = std::packaged_task<decltype(func(args...))()>(std::bind(func, args...));
  auto handle = task.get_future();
  std::thread th(std::move(task)); // here
  if (handle.wait_for(max_time) == std::future_status::timeout) {
    th.detach(); // and here
    throw std::runtime_error("timeout");
  } else { // and here
    th.detach();
    return handle.get();
  }
}

我可以安全地从std::thread获取内部std::future并将其分离吗?我猜它是明显的UB。 waiter()函数旨在获取任何可调用对象,调用它并在任何

时停止工作
  1. 达到超时
  2. 功能停止工作并返回结果
  3. 是真的。我试图在很多方面做到这一点,但总有一个问题。我意识到问题是C ++ 14没有流程支持。 第一次尝试:

    template <typename func_t, typename ... Args>
    auto waiter (func_t func, const Args &... args) -> decltype(func(args...)) {
      const static std::chrono::milliseconds max_time(10);
      decltype(func(args...)) result;
      std::mutex mtx;
      std::unique_lock<std::mutex> lock(mtx);
      std::condition_variable cv;
    
      thread th([&] {
          result = func(args...);
          cv.notify_all();
      });
    
      auto waiting_result = cv.wait_for(lock, max_time);
      th.detach();
      if (waiting_result == std::cv_status::timeout) {
        throw std::runtime_error("timeout");
      }
      return result;
    }
    

    这里的问题是在抛出异常后,std::thread th仍在使用被杀死的引用运行。第二次尝试:

    template <typename func_t, typename ... Args>
    auto waiter (func_t func, const Args &... args) ->     decltype(func(args...)) {
      const static std::chrono::milliseconds max_time(10);
      auto handle = std::async(std::launch::async, func, args ...);
      if (handle.wait_for(max_time) == std::future_status::timeout) {
        throw std::runtime_error("timeout");
      } else {
        return handle.get();
      }
    }
    

    此问题是(据我所知)std::async::~async()在其内部线程上调用某种std::thread::join(),主线程仍在等待std::asynchttp://melpon.org/wandbox/permlink/Cyd2hYJCQSIxETqL 傻一个。

1 个答案:

答案 0 :(得分:1)

您可以像第一次尝试一样分离线程,但是,正如您所说,线程将继续分离,直到它自己完成。

第二次尝试的问题是std::future返回的std::async有点特殊,因为它的析构函数将block until the thread finishes execution(与常规std::future的析构函数不同)

我担心在C ++中,如果不杀死所有线程,就不可能安全地终止单个线程。问题产生于在执行期间在任意点安全地展开堆栈的困难。如果让我们说,放卷应该在一个不合适的地方进行,如ctor或dtor,它会破坏对象存储持续时间的规则。

有关详细信息,请参阅this answer