STD :: Promise Set_exception两次导致分段故障

std::promise set_exception twice cause Segmentation fault

本文关键字:两次 分段 故障 Set Promise exception STD      更新时间:2023-10-16

假设我有一种调用不稳定第三方服务的方法,所以我添加了此通话的超时,说10秒。这是我尝试的:

int process()
{
    std::promise<int> promise;
    std::future<int> future = promise.get_future();
    std::thread([&]
    {
        try
        {
            int result = call_third_party_service();
            promise.set_value(result);
        }
        catch (std::exception&) //call_thrid_party_service can throw exceptions
        {
            promise.set_exception(std::current_exception());
        }
    }).detach();
    auto status = future.wait_for(std::chrono::seconds(10));
    if (status == std::future_status::timeout)
    {
        promise.set_exception(time_out_exception);
    }
    return future.get();
}
int main()
{
    try
    {
        int result = process();
    }
    catch(const std::exception& e)
    {
        //print
    }
    //blocks the thread to see what happens
    std::this_thread::sleep_for(std::chrono::minutes(1));        
    return 0;
}

call_third_party_service不响应时(假设它会在30秒后抛出一个例外情况(,status == std::future_status::timeout在等待10秒后命中,然后promise.set_exception工作,而一切看起来都不错。但是,当call_third_party_service引发异常时,再次promise.set_exception,因此分段故障。实施此模式的正确方法是什么?

按照Frax的建议,您应该将promise移至lambda中,并在future乘以时直接抛出异常:

int process() {
  std::promise<int> promise;
  std::future<int> future = promise.get_future();
  // move ownership of the promise into thread
  std::thread([prom = std::move(promise)]() mutable {
    try {
      int result = call_third_party_service();
      prom.set_value(result);
    } catch (std::exception&)  // call_thrid_party_service can throw exceptions
    {
      prom.set_exception(std::current_exception());
    }
  }).detach();
  auto status = future.wait_for(std::chrono::seconds(10));
  if (status == std::future_status::timeout) {
    // This exception is not part of an asynchronous computation and 
    // should be thrown immediately
    throw time_out_exception("timed out");
  }
  return future.get();
}
int main() {
  try {
    int result = process();
  } catch (const std::exception& e) {
    // print
  }
  // blocks the thread to see what happens
  std::this_thread::sleep_for(std::chrono::minutes(1)); 
  return 0;
}