简体   繁体   English

我需要在此服务器模型中使用boost :: strand吗?

[英]Do I need to use a boost::strand in this server model?

I've been coding this server for quite some time now. 我已经为这个服务器编码了一段时间了。 I am calling io_service::run from more than 1 thread, but I am not sure if I ned to use strand here. 我正在从1个以上的线程中调用io_service :: run,但是我不确定是否需要在这里使用strand。 Since I am never calling async_read more than once. 由于我从未多次调用async_read。 Though it is possible that I call async_write more than once if other connections need to send something to others. 虽然如果其他连接需要向其他人发送内容,则我可能多次调用async_write。 This is the code I have so far 这是我到目前为止的代码

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()));
}

I am not sure wheter this is threadsafe or not. 我不确定这是否是线程安全的。 If only the send part is not threadsafe since I can send more than 1 packet at once (which is going to happen) should I only use a strand there? 如果仅发送部分不是线程安全的,因为我可以一次发送多个数据包(这将要发生),我是否应该仅在其中使用链?

Gz GZ

Yes, you need a strand . 是的,您需要strand

As noted in the tcp::socket documentation, concurrent calls on the same socket (ie shared object) is not thread safe. tcp::socket文档中所述,同一套接字(即共享对象)上的并发调用不是线程安全的。 However, it is safe to have multiple asynchronous operations pending on an object. 但是,在一个对象上进行多个异步操作是安全的。 Thus, this is safe: 因此,这是安全的:

thread_1                             | thread_2
--------------------------------------+---------------------------------------
socket.async_receive(...);            |
socket.async_write_some(...);         |

and this is safe: 这是安全的:

thread_1                             | thread_2
--------------------------------------+---------------------------------------
socket.async_receive(...);            |
                                      | socket.async_write_some(...);

but this is specified as not being safe: 但这被指定为不安全:

thread_1                             | thread_2
--------------------------------------+---------------------------------------
socket.async_receive(...);            | socket.async_write_some(...);
                                      |

Furthermore, the send_mut mutex in Session::SendPacket() provides no real safety to m_socket . 此外, Session::SendPacket()send_mut互斥量不能为m_socket提供真正的安全性。 The boost::asio::async_write() operation is a composed operation , 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()函数的零个或多个调用组成 Due to the lifespan of the lock and the behavior of asynchronous operations, the lock does not guarantee that the mutex will be held during any or all of the async_write_some() operations. 由于锁的寿命和异步操作的行为,该锁不能保证在任何或所有async_write_some()操作期间都将保持互斥锁。

For more details on thread safety and strands, consider reading this answer. 有关线程安全和线束的更多详细信息,请考虑阅读答案。


Also, be aware that once an async_write() operation has been initiated on a stream, the program must ensure that no other write occurs on the stream until the initial operation's completion handler has been invoked: 另外,请注意,一旦在流上启动了async_write()操作,程序必须确保在调用初始操作的完成处理程序之前,不会在流上发生其他写操作:

The program must ensure that the stream performs no other write operations (such as async_write , the stream's async_write_some function, or any other composed operations that perform writes) until this operation completes. 程序必须确保该流完成之前,该流不执行其他任何写操作(例如async_write ,流的async_write_some函数或任何其他执行写操作的组合操作)。

If multiple writes need to be performed, then consider queuing up the writes, as shown in this answer. 如果需要执行多次写入,请考虑对写入进行排队, 如此答案所示。 This type of solution may also make managing the lifespan of the packet object's underlying buffer easier, as the queue will own a copy of the data, meeting the async_write() operation's requirement that the buffer's underlying memory blocks remain valid until the completion handler is called. 这种类型的解决方案还可以使管理packet对象的基础缓冲区的寿命变得更加容易,因为队列将拥有数据的副本,满足async_write()操作的要求,即缓冲区的基础内存块在调用完成处理程序之前一直保持有效。 。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM