现在,我有一个Connection
类,如下所示(无关的东西被省略了):
class Connection : public std::enable_shared_from_this<Connection> {
public:
virtual void write() {
socket_->async_write_some(boost::asio::buffer(buffer_.data(),
buffer_.size()),
std::bind(&Connection::on_written,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2));
}
void on_written(const boost::system::error_code& e, std::size_t length) {
if(e) {
// handle error here
return;
}
buffer_.consume(length);
}
void add_to_buf(const std::string& data) {
// add the string data to buffer_ here
}
private:
boost::asio::io_service& service_;
std::unique_ptr<socket> socket_;
boost::asio::streambuf buffer_;
};
如您所见,
write()
操作将在buffer_
中写入数据,并且仅在写操作完成处理程序中清除buffer_
。但是,问题来了,现在我有以下调用代码(注意:它是多线程的):Connection conn;
// initialization code here
conn.add_to_buf("first ");
conn.write();
conn.add_to_buf("second");
conn.write();
我想要的输出是
first second
,但是有时输出可能是first first second
。它在第二个操作开始但尚未调用第一个完成处理程序时发生。我已经读过有关strand
进行序列化的内容,但是,它只能序列化任务,不能序列化完成处理程序和任务。可能有人建议在第一个的完成处理程序中调用第二个写操作,但是根据设计,这无法实现。
那么,有什么建议吗?也许是对
buffer_
的锁定? 最佳答案
锁定缓冲区本身不会改变任何东西。如果在第一次写入完成之前调用write,它将再次发送相同的数据。在我看来,最好的方法是删除add_to_buf
方法,并坚持使用write
函数,该函数既可以执行此操作,又可以将数据添加到缓冲区中,并在必要时触发发送。
class Connection : public std::enable_shared_from_this<Connection> {
public:
virtual void write(const std::string& data) {
std::lock_guard<std::mutex> l(lock_);
bool triggerSend = buffer_.size() == 0;
// add data to buffer
if (triggerSend) {
do_send_chunk();
}
}
void on_written(const boost::system::error_code& e, std::size_t length) {
if (e) {
// handle error here
return;
}
std::lock_guard<std::mutex> l(lock_);
buffer_.consume(length);
if (buffer_.size() > 0) {
do_send_chunk();
}
}
private:
void do_send_chunk() {
socket_->async_write_some(boost::asio::buffer(buffer_.data(),
buffer_.size()),
std::bind(&Connection::on_written,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2));
}
boost::asio::io_service& service_;
std::unique_ptr<socket> socket_;
boost::asio::streambuf buffer_;
std::mutex lock_;
};
这个想法是,写功能检查缓冲区中是否还有剩余数据。在这种情况下,不必或早或晚调用
do_send_chunk
就会触发on_written
调用,这将导致另一个do_send_chunk
,因为新数据将保留在缓冲区中,并且if(buffer_.size() > 0)
在on_written
内部为true。但是,如果没有数据,则必须触发发送操作。关于c++ - 通过多线程共享缓冲区 boost asio async_write,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22755801/