即使使用strand,async_writes的排序也是错误的

时间:2017-08-29 12:41:18

标签: c++ multithreading sockets boost boost-asio

我正在编写一个程序,将读取的数据转发给另一个对等方。 我有一个方法,在每次读取套接字数据后调用。此方法将数据发布到一个链中以将其写回另一个对等方。当发送大块数据时,应用程序发回的数据与收到的数据不同,问题是数据不再被订购。这只是在boost :: asio :: io_service中使用多个线程的情况。

在套接字上读取某些数据时会调用handleGatewayReply。 此时(1),在文件中写入数据后,我可以看到数据仍然是有序的。 之后,正在调用postBackendReply并且数据仍然是有序的(2)。 但是在SessionConnection :: postReply中,如果我将数据刷新到文件(3),我可以看到数据不再被排序。 我不明白为什么订单在这一点上丢失了,我试图在handleGatewayReply和postBackendReply中使用一个strand(如代码所示),但行为仍然是相同的。

抱歉,我无法提交一个Minimal,Complete和Verifiable示例,因为该bug很难发现,需要多线程转发大量数据。

  void Reply::handleGatewayReply(std::stringstream* stream)
  {
    // Flush data to file (1)
    m_strand.post(std::bind([=]() {  
        postBackendReply(*stream);
      delete stream;
    }
    }));

  }

void Reply::postBackendReply(const std::stringstream& stream)
  {
    auto buffer = std::make_shared<Buffer>();
    buffer->m_buffers.push_back(stream.str());
    // Flush data to file (2)
    auto connection = m_request->connection();
    if (connection) {
//    connection->postReply(buffer); // doesn't work either
          m_strand.post(std::bind(&SessionConnection::postReply, connection,buffer));
    }

  }


  void SessionConnection::postReply(BufferPtr buffer)
  {
      // Flush data to file (3)
      m_ioService.post(
        m_ostrand.wrap(
          std::bind(&SessionConnection::sendNext, 
                    shared_from_this(), buffer)));
    }
  }

1 个答案:

答案 0 :(得分:4)

使用链时:

  1. 永远不要将任何处理程序直接发布到io_service - 这可以保证失去排序并破坏并发保证。

  2. strand::wrap每个异步处理程序。

  3. 在(包装)处理程序中,如果您需要强制订单,dispatch到链。如果发布的处理程序在将来的某个时间点执行时仍然有效,则只有post

  4. 示例:

    thing.async_op(mystrand.wrap([self = shared_from_this()](auto&& error){
        self->mystrand.dispatch(&must_be_done_now_A);
        self->mystrand.post(&may_be_done_out_of_order_B);
        self->mystrand.dispatch(&must_be_done_now_C);
    });
    

    执行顺序为:

    1. thing&#39; s处理程序
    2. must_be_done_now_A
    3. must_be_done_now_C
    4. thing&#39;}处理程序完成
    5. 在此期间进入io_service的任何其他内容
    6. may_be_done_out_of_order_B