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

时间:2014-05-27 17:50:19

标签: c++ boost boost-asio

我在一个类中有以下两个成员函数。 _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));
    }
}

1 个答案:

答案 0 :(得分:2)

您的代码锁定了调用async_write()的互斥锁,并在处理程序中解锁它。如果这些操作发生在不同的线程中,那么这将违反unlock() preconditions(当前线程拥有互斥锁)。这可能会导致您的僵局。通常,分离的锁定和解锁通常表示设计欠佳。

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

写功能:

  • 锁定互斥锁。
  • 将缓冲区推入队列。
  • 如果队列中只包含一个元素,请在前面的元素上调用async_write
  • 解锁互斥锁(理想情况是通过scoped_lock超出范围)。

写处理程序:

  • 锁定互斥锁。
  • 从队列弹出缓冲区(并释放它)。
  • 如果队列不为空,请在前面元素上调用async_write
  • 解锁互斥锁(理想情况是通过scoped_lock超出范围)。

使用这种方法,锁定是本地化的,没有机会发生死锁。 @ TannerSansbury在评论中使用链进行同步而不是互斥的指针将起到类似的作用 - 它隐含地为链中运行的任何函数提供排除。

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