为什么这段代码会阻塞不执行?

时间:2015-06-16 08:13:43

标签: c++ multithreading error-handling try-catch

未运行catch处理程序。但为什么呢?

如果thread ttry块之前启动,则捕获处理程序将运行。

如果catch块的类型与抛出的类型不匹配,则程序退出,说明线程以未捕获的异常终止,表明异常已处理,但catch块未运行。

#include <iostream>
#include <thread>

using namespace std;

void do_work() {}

int main() {
  std::cerr << "RUNNING" << std::endl;
  try {
    thread t(do_work);
    std::cerr << "THROWING" << std::endl;
    throw logic_error("something went wrong");
  } catch (logic_error e) {
    std::cerr << "GOTCHA" << std::endl;
  }

  return 0;
}

编译命令:

c++ -std=c++14 -pthread -pedantic -Wall -Wextra -O0 scratch.cpp -o scratch

2 个答案:

答案 0 :(得分:5)

你忘了加入主题:

try {
  thread t(do_work);
  t.join();                                    // <<< add this
  std::cerr << "THROWING" << std::endl;
  throw logic_error("something went wrong");
} catch (logic_error e) {
  std::cerr << "GOTCHA" << std::endl;
}

A joinable thread that goes out of scope, causes terminate to be called。因此,您需要在超出范围之前调用joindetach

答案 1 :(得分:2)

C ++ 11,30.3.1.3中,线程析构函数标准说

  

如果是joinable()则终止(),否则没有效果。 [注意:隐式分离或连接其析构函数中的joinable()线程可能导致无法调试正确性(用于分离)或性能(用于连接)仅在引发异常时遇到的错误。因此,程序员必须确保在线程仍可连接时永远不会执行析构函数。 - 后注]

因此,一旦调用了线程析构函数,你的程序terminate就会因为范围结束而且永远不会执行catch逻辑。

如果您希望程序从线程范围中捕获异常但在线程仍可连接时抛出,则需要在线程本身的范围内捕获它,join或{{3线程并重新抛出任何被捕获的东西。

try 
{
  std::thread t(foo);
  try
  {
    std::cerr << "THROWING" << std::endl;
    throw std::logic_error("something went wrong");
  }
  catch (...) // catch everything
  {
    t.join(); // join thread
    throw; // rethrow
  }
  t.join();
}
catch (std::logic_error & e) 
{
  std::cerr << "GOTCHA: " << e.what() << std::endl;
}