async_write()
。它使用async_write_some
按块发送数据,并且这些块可以交错。因此,用户需要注意不要同时调用async_write()
。
有比这个伪代码更好的解决方案吗?
void send(shared_ptr<char> p) {
boost::mutex::scoped_lock lock(m_write_mutex);
async_write(p, handler);
}
我不喜欢在很长一段时间内阻止其他线程的想法(在我的应用程序中有~50Mb发送)。
这可能是有用的吗?
void handler(const boost::system::error_code& e) {
if(!e) {
bool empty = lockfree_pop_front(m_queue);
if(!empty) {
shared_ptr<char> p = lockfree_queue_get_first(m_queue);
async_write(p, handler);
}
}
}
void send(shared_ptr<char> p) {
bool q_was_empty = lockfree_queue_push_back(m_queue, p)
if(q_was_empty)
async_write(p, handler);
}
我更愿意找到一个随时可用的食谱食谱。处理无锁是不容易的,会出现许多微妙的错误。
答案 0 :(得分:4)
禁止使用async_write() 从不同的同时召唤 线程
这句话不太正确。应用程序可以同时自由调用async_write
,只要它们位于不同的socket
个对象上。
有没有比这更好的解决方案 伪码?
void send(shared_ptr<char> p) { boost::mutex::scoped_lock lock(m_write_mutex); async_write(p, handler); }
由于async_write
立即返回,这可能无法实现您的意图。如果您希望在整个写操作期间锁定互斥锁,则需要将scoped_lock
保留在范围内,直到调用完成处理程序。
针对此问题有更好的解决方案,该库具有使用strand概念的内置支持。它非常适合这种情况。
一条链被严格定义 顺序调用事件 处理程序(即没有并发 调用)。使用股线允许 在多线程中执行代码 程序无需显式 锁定(例如使用互斥锁)。
在此处使用显式链将确保您的处理程序仅由调用io_service::run()
的单个线程调用。在您的示例中,m_queue
成员将受到链的保护,从而确保对传出消息队列的原子访问。在向队列添加条目后,如果大小为1,则表示没有未完成的async_write
操作正在进行中,并且应用程序可以启动通过链包装的操作。如果队列大小大于1,则应用程序应等待async_write
完成。在async_write
完成处理程序中,弹出队列中的条目并根据需要处理任何错误。如果队列不为空,则完成处理程序应从队列的前面启动另一个async_write
。
这是一个更简洁的设计,可以在您的类中使用互斥体,因为它使用内置的Asio结构。这个other answer I wrote有一些代码实现了这个设计。
答案 1 :(得分:1)
我们通过在socket对象中保存一个单独的数据队列来解决这个问题。当要写入的第一段数据“排队”时,我们开始async_write()
。在async_write
的完成处理程序中,如果仍有数据需要传输,我们会启动后续的async_write
操作。