捕获异常

捕获异常

问题描述:

我有我的应用程序的主回路控制,我做启动一个线程来处理ASIO工作如下:捕获异常

void AsioThread::Run() 
{ 
    try 
    { 
     /* 
     * Start the working thread to io_service.run() 
     */ 
     boost::asio::io_service::work work(ioService); 
     boost::thread t(boost::bind(&boost::asio::io_service::run, &ioService)); 
     t.detach(); 

     while (true) 
     { 

      // Process stuff related to protocol, calling 
      // connect_async, send_async and receive_async 
     } 
    } 
    catch (std::runtime_error &ex) 
    { 
     std::cout << "ERROR IN FTP PROTOCOL: " << ex.what() << std::endl; 
    } 
    catch (...) 
    { 
     std::cout << "UNKNOWN EXCEPTION." << std::endl; 
    } 

在异步操作,处理程序被调用,有时我也引发异常这些处理程序,如:

void AsioThread::ReceiveDataHandler(const boost::system::error_code& errorCode, std::size_t bytesTransferred) 
{ 
     std::cout << "Receive data handler called. " << bytesTransferred << " bytes received." << std::endl; 

     if (errorCode) 
     { 
      std::cout << "Error receiving data from server." << std::endl; 
     } 

     rxBufferSize = bytesTransferred; 

     /* 
     * Check for response 
     */ 
     std::string msg(rxBuffer); 
     if (msg.substr(0, 3) != "220") 
       throw std::runtime_error("Error connecting to FTP Server"); 
    } 

我的问题是,异步处理器(AsioThread::ReceiveDataHandler)内抛出的异常不是由主处理循环try...catch块逮住在AsioThread::Run。当然,这是因为工作线程t在另一个线程上,并且在运行时导致执行错误。

如何从分离的boost::asio::io_service::work线程收到异常?我怎样才能构建我的代码来使这个逻辑起作用?

感谢您的帮助。

+1

为什么你有一个单独的while (true)事件循环?你可以使用asio事件循环来做所有事情?在那种情况下加入线程。如果可能会失效,请创建一个io_service :: work对象。 – Ralf

+0

我需要事件循环,因为它可以用作网络逻辑的状态处理器...不能没有它。 – Mendes

+0

不知道我是否理解你,但通常在异步回调中处理协议状态。这不需要有一个单独的事件循环。例如,在async_connect之后的回调函数中,你将被连接等。事件处理程序开始下一个异步操作,例如async_connect处理程序也可以启动读取和写入。 – Ralf

您可以在工作线程中捕获异常,将它们保存到由两个线程共享的队列变量中,并在主线程中定期检查该队列。

要使用队列,您需要先将异常转换为常用类型。您可以使用std::exceptionstring或任何最适合您的情况。如果您绝对需要保留原始异常类的信息,则可以使用boost::exception_ptr

变量,你需要(这些的AsioThread可能是成员):

boost::mutex queueMutex; 
std::queue<exceptionType> exceptionQueue; 

运行该功能在工作线程:

void AsioThread::RunIoService(){ 
    try{ 
     ioService.run(); 
    } 
    catch(const exceptionType& e){ 
     boost::lock_guard<boost::mutex> queueMutex; 
     exceptionQueue.push(e); 
    } 
    catch(...){ 
     boost::lock_guard<boost::mutex> queueMutex; 
     exceptionQueue.push(exceptionType("unknown exception")); 
    } 
} 

启动辅助线程这样的:

boost::thread t(boost::bind(&AsioThread::RunIoService, this)); 
t.detach(); 

在主线程中:

while(true){ 
    // Do something 

    // Handle exceptions from the worker thread 
    bool hasException = false; 
    exceptionType newestException; 
    { 
     boost::lock_guard<boost::mutex> queueMutex; 
     if(!exceptionQueue.empty()){ 
      hasException = true; 
      newestException = exceptionQueue.front(); 
      exceptionQueue.pop(); 
     } 
    } 
    if(hasException){  
     // Do something with the exception 
    } 
} 

This blog post实现了一个线程安全队列,您可以使用它来简化保存异常;在这种情况下,你不需要单独的互斥体,因为这将在队列类中。

+0

这是一个好主意,但我没有编码工作线程......它由'boost :: asio'处理。请参阅'boost :: thread t(boost :: bind(&boost :: asio :: io_service :: run,&ioService));'...... – Mendes

+0

@Mendes虽然您可能无法控制io_service :: run() ',你可以控制线程的入口点。考虑创建一个在try/catch块内调用'io_service.run()'的函数,根据需要传播异常,并将此函数指定为线程入口点。 –

+0

@Mendes我改变了我的答案,它现在应该在你的情况下工作。 –