Boost Asio:在 mutl-thread 中使用 streambuf 和 async_write 时很奇怪

Boost Asio: Strange when use streambuf and async_write in mutl-thread

提问人:junya 提问时间:6/15/2021 更新时间:6/15/2021 访问量:262

问:

我的程序在发送数据时有一个缓冲区。与其每次都直接调用 async_write 发送小包,不如尽量让 send 方法快速返回,使用 streambuf 作为发送缓冲区,尝试发送大包。

现在遇到的问题是,当多个线程同时调用 send 时,另一端接收到重复数据包或凌乱数据的概率很小。这是我的代码:

void ClientConnection::send(const string* buffer, function<void (bool status)> callback) {
    {
        unique_lock<mutex> lck(*_ioLockPtr);
        ostream os(_sendBufferPtr.get());
        os << *buffer;
    }
    delete buffer;
    callback(true);
    _sendBuffer();
}

void ClientConnection::_sendBuffer() {
    unique_lock<mutex> lck(*_ioLockPtr);

    size_t bufferSize = _sendBufferPtr->size();
    if (!bufferSize || _sendingBufferCount > 0) {
        return;
    }

    ++_sendingBufferCount;
    async_write(*_socketPtr, _sendBufferPtr->data(), boost::asio::transfer_exactly(bufferSize), boost::bind(&ClientConnection::_handleWrite, 
        shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));

    _sendBufferPtr->consume(bufferSize);
}

void ClientConnection::_handleWrite(const boost::system::error_code& error, size_t bytes_transferred) {
    if (!error) {
        unique_lock<mutex> lck(*_ioLockPtr);

        size_t bufferSize = _sendBufferPtr->size();

        if (bufferSize) {
            async_write(*_socketPtr, _sendBufferPtr->data(), boost::asio::transfer_exactly(bufferSize), boost::bind(&ClientConnection::_handleWrite, 
                shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));

            _sendBufferPtr->consume(bufferSize);

        } else {
            --_sendingBufferCount;
        }
    } else {
        {
            unique_lock<mutex> lck(*_ioLockPtr);
            --_sendingBufferCount;
        }
        _close();
    }
}

相关变量定义如下:

shared_ptr<boost::asio::streambuf> _sendBufferPtr;
uint8_t _sendingBufferCount;

请帮我了解如何解决这个问题,谢谢!

C++ 加速 ASIO Streambuf

评论


答:

2赞 sehe 6/15/2021 #1

现在遇到的问题是,当多个线程同时调用 send 时

根据文档,这是严格禁止的:

此操作是通过对流的 async_write_some 函数的零次或多次调用来实现的,称为组合操作。程序必须确保流在此操作完成之前不执行其他写入操作(例如async_write、流的async_write_some函数或执行写入的任何其他组合操作)。

若要序列化异步操作,可能需要使用链。