C++ 我需要在这个服务器模型中使用boost::strand吗?

C++ 我需要在这个服务器模型中使用boost::strand吗?,c++,boost-asio,C++,Boost Asio,我已经为这个服务器编写代码很长时间了。我正在从多个线程调用io_service::run,但我不确定是否需要在这里使用strand。因为我从不调用async\u多次读取。尽管如果其他连接需要向其他连接发送某些内容,我可能会多次调用async_write。这是我目前掌握的代码 void Session::RecvPacket() { boost::asio::async_read(m_socket, boost::asio::buffer(m_recv_buffer, len),

我已经为这个服务器编写代码很长时间了。我正在从多个线程调用io_service::run,但我不确定是否需要在这里使用strand。因为我从不调用async\u多次读取。尽管如果其他连接需要向其他连接发送某些内容,我可能会多次调用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()));
}
void会话::RecvPacket()
{
boost::asio::async_read(m_套接字,boost::asio::buffer(m_recv_buffer,len),
boost::bind(&Session::OnRead,this,boost::asio::占位符::error,
boost::asio::占位符::字节(已传输);
}
无效会话::OnRead(const boost::system::错误\u代码和e、大小\u t数据包\u长度、大小\u t字节\u传输)
{
如果(e | |字节_传输!=数据包_长度)
{
如果(e==boost::asio::error::operation\u中止)
返回;
停止();
返回;
}
//做点什么,很可能会寄回一个包
RecvPacket();
}
无效会话::发送数据包(数据包和p)
{
boost::mutex::作用域锁定(send\u mut);
dword len=p.lengh();
m_crypt->makeheader(p.GetRaw().get(),static_cast(len-4));
m_crypt->encrypt(p.GetRaw().get()+4,len-4);
boost::asio::async_write(m_套接字,boost::asio::buffer(p.GetRaw().get(),len),
boost::bind(&Session::OnPacketSend),this,len,boost::asio::placeholders::error,
boost::asio::占位符::传输的字节数,p.GetRaw();
}
我不确定这是不是线程安全。如果只有发送部分不是线程安全的,因为我可以一次发送多个数据包(这将要发生),那么我应该只在那里使用一个数据链吗


Gz

是的,您需要一根
钢绞线

如文档中所述,对同一套接字(即共享对象)的并发调用不是线程安全的。但是,在一个对象上挂起多个异步操作是安全的。因此,这是安全的:

thread_1 | thread_2 --------------------------------------+--------------------------------------- socket.async_receive(...); | socket.async_write_some(...); | thread_1 | thread_2 --------------------------------------+--------------------------------------- socket.async_receive(...); | | socket.async_write_some(...); 螺纹1 |螺纹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(...); 螺纹1 |螺纹2 --------------------------------------+--------------------------------------- socket.async_receive(…)| |socket.async_write_some(…); 但这被规定为不安全:

thread_1 | thread_2 --------------------------------------+--------------------------------------- socket.async_receive(...); | socket.async_write_some(...); | 螺纹1 |螺纹2 --------------------------------------+--------------------------------------- socket.async_receive(…);|socket.async_write_some(…); | 此外,
Session::SendPacket()
中的
send_mut
互斥锁对
m_socket
没有真正的安全性。该操作是一个组合操作,由对
m_socket.async_write_some()
函数的零个或多个调用组成。由于锁的使用寿命和异步操作的行为,锁不能保证在任何或所有
async\u write\u some()
操作期间保持互斥锁

有关螺纹安全和绞线的更多细节,请考虑阅读答案。


另外,请注意,一旦在流上启动了
async_write()
操作,程序必须确保在调用初始操作的完成处理程序之前,流上不会发生其他写入操作:

程序必须确保流不执行任何其他写入操作(例如
异步写入
、流的
异步写入
函数或执行写入的任何其他组合操作),直到此操作完成


如果需要执行多个写入,则考虑排队写入,如答案所示。这种类型的解决方案还可以使管理

数据包
对象的底层缓冲区的寿命更容易,因为队列将拥有数据的副本,满足
异步写入()
操作的要求,即缓冲区的底层内存块在调用完成处理程序之前保持有效。

是,您需要一个

如文档中所述,对同一套接字(即共享对象)的并发调用不是线程安全的。但是,在一个对象上挂起多个异步操作是安全的。因此,这是安全的:

thread_1 | thread_2 --------------------------------------+--------------------------------------- socket.async_receive(...); | socket.async_write_some(...); | thread_1 | thread_2 --------------------------------------+--------------------------------------- socket.async_receive(...); | | socket.async_write_some(...); 螺纹1 |螺纹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(...); 螺纹1 |螺纹2 --------------------------------------+--------------------------------------- socket.async_receive(…)| |socket.async_write_some(…); 但这被规定为不安全:

thread_1 | thread_2 --------------------------------------+--------------------------------------- socket.async_receive(...); | socket.async_write_some(...); | 螺纹1 |螺纹2 --------------------------------------+--------------------------------------- socket.async_receive(…);|socket.async_write_some(…); | 此外,
Session::SendPacket()
中的
send_mut
互斥锁对
m_socket
没有真正的安全性。该操作是一个组合操作,由对
m_socket.async_write_some()
函数的零个或多个调用组成。由于锁的使用寿命和异步操作的行为,锁不能保证在任何或所有
async\u write\u some()
操作期间保持互斥锁

有关螺纹安全和绞线的更多细节,请考虑阅读答案。


另外,请注意,一旦在流上启动了
async_write()
操作,程序必须确保在初始操作完成之前,流上不会发生其他写入操作