并发async_write。有没有等待的解决方案?

时间:2011-05-07 08:06:47

标签: c++ boost-asio

禁止从不同的线程同时调用

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

我更愿意找到一个随时可用的食谱食谱。处理无锁是不容易的,会出现许多微妙的错误。

2 个答案:

答案 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操作。