c++ - 从作为分离线程运行的 boost::asio::io_service::work 捕获异常

标签 c++ multithreading boost boost-asio

我有我的应用程序主循环控制,我在其中启动一个线程来处理 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 的异常线 ?我如何构建我的代码以使这个逻辑起作用?

感谢您的帮助。

最佳答案

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

要使用队列,您需要首先将异常转换为通用类型。您可以使用 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实现一个线程安全队列,您可以使用它来简化保存异常;在这种情况下,您不需要单独的互斥锁,因为它位于队列类内部。

关于c++ - 从作为分离线程运行的 boost::asio::io_service::work 捕获异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35814249/

相关文章:

c++ - 我可以避免在一系列函数调用中使用模板消歧器吗?

c++ - 为什么 C++20 std::condition_variable 不支持 std::stop_token?

c++ - 无限循环直到应用程序收到信号

c++ - Boost.Interprocess 是否牺牲性能来实现可移植性

c++ - 使用 boost::function_types 的函数调用约定

c++ - 作为一个没有CS学位的程序员,我是否必须广泛学习C++?

c++ - 如何根据用户调整二维网格大小?

c# - 是否允许在线程之间缓存/重用 Thread.GetNamedSlot?

java - 在加入其他线程时被打断

c++ - 从 boost::ptr_vector 获取模板参数