我有一个非常奇怪的问题。我编写了一个服务器,它将从第三方接收的数据写入连接的客户端。服务器暂时写入客户端,但过了一段时间,async_write失败或写入永远不会返回。对于我的程序,如果async_write永远不会返回,则不会发生后续写入,我的服务器将排队从第三方收到的数据,直到所有内容都爆炸。
我在下面提供了我的代码:
void ClientPartitionServer::HandleSignal(const CommonSessionMessage& message, int transferSize) {
boost::lock_guard<boost::mutex> lock(m_mutex);
if(m_clientSockets.size() != 0) {
TransferToQueueBuffer(message.GetData(), transferSize);
}
if(m_writeCompleteFlag) {
// TransferToWriteBuffer();
for(vector<boost::asio::ip::tcp::socket*>::const_iterator i = m_clientSockets.begin(); i != m_clientSockets.end(); ++i) {
WriteToClient(*i);
}
}
}
void ClientPartitionServer::WriteToClient(boost::asio::ip::tcp::socket* clientSocket) {
m_writeCompleteFlag = false;
cout << "Iniating write: " << m_identifier << endl;
boost::asio::async_write(
*clientSocket,
boost::asio::buffer(m_queueBuffer.get(), m_queueBufferSize),
boost::bind(
&ClientPartitionServer::HandleWrite, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred
));
}
void ClientPartitionServer::HandleWrite(const boost::system::error_code& ec, size_t bytes_transferred) {
boost::lock_guard<boost::mutex> lock(m_mutex);
if(ec != 0) {
cerr << "Error writing to client: " << ec.message() << " " << m_identifier << endl;
// return;
cout << "HandleWrite Error" << endl;
exit(0);
}
cout << "Write complete: " << m_identifier << endl;
m_writeCompleteFlag = true;
m_queueBuffer.reset();
m_queueBufferSize = 0;
}
任何帮助都将不胜感激。
谢谢。
答案 0 :(得分:4)
在没有看到所有代码的情况下很难说,但是对于我来说,如果你在多个(甚至一个)WriteToClient
个调用中持有互斥锁,那将是一个危险信号。通常在I / O上保持任何类型的锁(即使是像这里一样的异步)也不利于性能,最坏的情况是加载时出现奇怪的死锁。如果异步写入完成内联并且您在同一个线程/调用堆栈中的HandleWrite
上回调,会发生什么?
我会尝试重构这个,以便在写入调用期间释放锁。
无论解决方案是什么,更一般的建议:
答案 1 :(得分:1)
使用strand来序列化对特定连接对象的访问。特别是,请查看strand::wrap()。要查看使用线索的其他示例,请查看few different timer examples(虽然该代码适用于任何async_*()
来电)。
答案 2 :(得分:0)
首先,我不同意这些注释表明在异步操作中持有锁是一个问题。
持有锁:
任何调用回调的函数都不好。
任何阻止操作都很糟糕。
async_write
明确保证既不阻止也不调用处理程序,所以握住锁定对我来说很好。
但是,我可以在您的代码中看到违反async_write
的其他要求的错误。在调用完成处理程序之前,不允许调用async_write
。这就是你违反的行为。
每当其中一个处理程序被调用时,m_writeCompleteFlag
就会设置为true
。这意味着您可能违反高负荷下其他一些N-1插座的async_write
规则。