[英]Do I need to use a boost::strand in this server model?
我已经为这个服务器编码了一段时间了。 我正在从1个以上的线程中调用io_service :: run,但是我不确定是否需要在这里使用strand。 由于我从未多次调用async_read。 虽然如果其他连接需要向其他人发送内容,则我可能多次调用async_write。 这是我到目前为止的代码
void Session::RecvPacket()
{
boost::asio::async_read(m_socket, boost::asio::buffer(m_recv_buffer, len),
boost::bind(&Session::OnRead, this, boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void Session::OnRead(const boost::system::error_code &e, size_t packet_length, size_t bytes_transferred)
{
if (e || bytes_transferred != packet_length)
{
if (e == boost::asio::error::operation_aborted)
return;
Stop();
return;
}
// do something and most likely send a packet back
RecvPacket();
}
void Session::SendPacket(packet &p)
{
boost::mutex::scoped_lock lock(send_mut);
dword len = p.Lenght();
m_crypt->makeheader(p.GetRaw().get(), static_cast<word>(len - 4));
m_crypt->encrypt(p.GetRaw().get() + 4, len - 4);
boost::asio::async_write(m_socket, boost::asio::buffer(p.GetRaw().get(), len),
boost::bind(&Session::OnPacketSend, this, len, boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred, p.GetRaw()));
}
我不确定这是否是线程安全的。 如果仅发送部分不是线程安全的,因为我可以一次发送多个数据包(这将要发生),我是否应该仅在其中使用链?
GZ
是的,您需要strand
。
如tcp::socket
文档中所述,同一套接字(即共享对象)上的并发调用不是线程安全的。 但是,在一个对象上进行多个异步操作是安全的。 因此,这是安全的:
thread_1 | thread_2 --------------------------------------+--------------------------------------- socket.async_receive(...); | socket.async_write_some(...); |
这是安全的:
thread_1 | thread_2 --------------------------------------+--------------------------------------- socket.async_receive(...); | | socket.async_write_some(...);
但这被指定为不安全:
thread_1 | thread_2 --------------------------------------+--------------------------------------- socket.async_receive(...); | socket.async_write_some(...); |
此外, Session::SendPacket()
的send_mut
互斥量不能为m_socket
提供真正的安全性。 , made up of zero or more call's to the m_socket.async_write_some()
function. boost::asio::async_write()
操作是一个 ,由对m_socket.async_write_some()
函数的零个或多个调用 。 由于锁的寿命和异步操作的行为,该锁不能保证在任何或所有async_write_some()
操作期间都将保持互斥锁。
有关线程安全和线束的更多详细信息,请考虑阅读此答案。
另外,请注意,一旦在流上启动了async_write()
操作,程序必须确保在调用初始操作的完成处理程序之前,不会在流上发生其他写操作:
程序必须确保该流完成之前,该流不执行其他任何写操作(例如
async_write
,流的async_write_some
函数或任何其他执行写操作的组合操作)。
如果需要执行多次写入,请考虑对写入进行排队, 如此答案所示。 这种类型的解决方案还可以使管理packet
对象的基础缓冲区的寿命变得更加容易,因为队列将拥有数据的副本,满足async_write()
操作的要求,即缓冲区的基础内存块在调用完成处理程序之前一直保持有效。 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.