当 asio::async_write 不调用处理程序时该怎么办?

What to do when asio::async_write doesn't call the handler?

本文关键字:程序 怎么办 处理 async asio write 调用      更新时间:2023-10-16

在一个类中有以下两个成员函数。_mtxWrite是我用来使写函数线程安全的互斥对象。在高负载期间,有时不会调用writeHandler。然后_mtxWrite不会被释放,导致死锁。检测这种情况并解决僵局的最佳方法是什么?

template <class TSession>
void write(boost::shared_ptr<TSession> pSession, 
    boost::shared_ptr<CInProtocolBase> pMessage)
{
    std::vector<unsigned char>* pData = new std::vector<unsigned char>;
    pMessage->serialize(*pData); 
    _mtxWrite.lock();
    boost::asio::async_write(_socket,boost::asio::buffer(&pData->at(0), 
        pData->size()),
        boost::bind(&this_type::writeHandler<TSession>,
        shared_from_this(),pSession,pData,boost::asio::placeholders::error));
}
template <class TSession>
void writeHandler(boost::shared_ptr<TSession> pSession, 
    std::vector<unsigned char>* pData,const boost::system::error_code& ec)
{
    delete pData;
    _mtxWrite.unlock();
    if(ec)
    {
        _socket.get_io_service().post(boost::bind(&TSession::errorHandler,
            pSession,ec));
    }
}

您的代码正在锁定一个互斥锁,其中async_write()被调用并在处理程序中解锁它。如果这些操作发生在不同的线程中,那么这将违反unlock()前提条件(当前线程拥有互斥锁)。这可能会导致死锁。通常,分离的锁定和解锁通常是次优设计的指示。

处理异步写操作的更好方法是使用队列。逻辑看起来像这样:

写功能:

  • 锁定互斥对象。
  • Push buffer到queue.
  • 如果队列只包含一个元素,则调用前面元素的async_write
  • 解锁互斥锁(理想情况下通过scoped_lock落在范围之外)。

编写处理程序:

  • 锁定互斥对象。
  • 从队列中弹出缓冲区(并释放它)
  • 如果队列不为空,则调用前面元素的async_write
  • 解锁互斥锁(理想情况下通过scoped_lock退出范围)。

使用这种方法锁定是本地化的,没有死锁的机会。@TannerSansbury在注释中指向使用链来同步而不是互斥锁的指针的工作原理类似——它隐式地为在链中运行的任何函数提供了排斥。

我从来没有遇到过写处理程序没有被调用的情况,最终确定这不是我自己的错误,但是您可以使用boost::asio::deadline_timer来监视这种情况,通过在调用async_write()时设置计时器并在写处理程序中取消它。

相关文章: