C++ 使用boost::asio异步模型进行套接字读取,多线程

C++ 使用boost::asio异步模型进行套接字读取,多线程,c++,multithreading,sockets,boost,boost-asio,C++,Multithreading,Sockets,Boost,Boost Asio,我的应用程序主线程(线程1)必须未被阻止运行。它需要通过套接字接收流式数据…数据将随着时间的推移不断从远程服务器到达。我对线程1的控制有限(这是一种插件类型的软件,用于提供线程1的大型主机应用程序) 因此,我在线程1上被调用,其中有一个指向缓冲区的指针,用于将数据放入缓冲区。如果没有来自套接字的传入数据,我可以只写零。需要至少有X字节的数据才能填充给定的缓冲区。如果套接字缓冲区中至少没有X字节(稍后将对此进行详细介绍),那么我可以再次用零填充它 由于我对线程1的控制有限,我相信我必须有一个线程2

我的应用程序主线程(线程1)必须未被阻止运行。它需要通过套接字接收流式数据…数据将随着时间的推移不断从远程服务器到达。我对线程1的控制有限(这是一种插件类型的软件,用于提供线程1的大型主机应用程序)

因此,我在线程1上被调用,其中有一个指向缓冲区的指针,用于将数据放入缓冲区。如果没有来自套接字的传入数据,我可以只写零。需要至少有X字节的数据才能填充给定的缓冲区。如果套接字缓冲区中至少没有X字节(稍后将对此进行详细介绍),那么我可以再次用零填充它

由于我对线程1的控制有限,我相信我必须有一个线程2来处理套接字接口(同意吗?)。假设我创建了该线程,并将其设置为与boost::asio async TCP非常相似。关注这个例子中的“读取”一方,考虑一下我创建了一个无休止的“读取器”(直到我杀死IoSoCub或线程2或一些这样的)。 它将数据堆积到数据存储中——一个用于缓冲区的简单静态数组。因为我不知道需要多少缓冲,所以我考虑使用向量类型的实现。boost实现这一点的方法似乎是使用boost::asio::streambuf,它以FIFO方式调整大小并运行(这很重要,因为我希望传入的数据保持有序)。它还具有输入序列和输出序列的概念。我的目标是使用这个…线程2将通过上面的代码将数据放入输出序列,而线程1将在运行时从输入序列读取数据,并发现它有超过X个字节。streambuf从输出到输入的内部复制是通过commit()完成的。但我的理解是boost::asio::streambuf通常不是线程安全的。可以用锁包装对streambuf(输入或输出序列)的所有访问以解决问题,但在套接字端……该锁必须在async_read_some和do_read之间保持,因为它在两者之间的某个点访问streambuf。我认为这将是线程2“大部分时间”的状态,因此锁对线程1的限制非常大(同样,线程1无法阻止,因此它必须“尝试”锁,并且很少获得它)

对于一个线程访问输出序列而另一个线程访问输入序列(?),boost::asio::streambuf似乎应该是安全的。我希望唯一的争用点是commit()。如果我可以控制提交(我不清楚我是否可以…我想可能是async_read自动完成的?),那么我可以锁定提交


有什么办法可以做我想做的事吗?诚然,我可能太专注于最小化副本。如果我允许另一个复制,那么似乎可以在线程1和线程2之间创建另一个线程锁定的缓冲区/队列(thread_buf)…在这里,do_read可以锁定、从streambuf复制到thread_buf、解锁、异步_read…等等。线程1将执行锁定,如果线程有足够的数据,请将其复制出来,然后解锁。

您能更清楚地说明问题是什么吗?理想情况下,这个问题会变得更短,因为我需要使用两个线程来解释为什么我需要使用两个线程……您可以在代码后面阅读段落。我想不出更短的了。第三段中的关键问题是“有什么方法可以完成我想做的事情吗?”听起来非常像是需要专门使用一个工作线程来泵送ASIO的run()循环,并使用某种形式的进程间通信(如futures)在主线程上推送读缓冲区——futures应该允许您避免几乎所有的显式锁定。不幸的是,ASIO不允许您在与调用run()的线程并发的线程中启动异步操作,而无需额外锁定,这是我在AFIO v2闪亮的新I/o反应器中修复的一件大事,它取代了ASIO。@Niall-谢谢。我想我可以放弃streambuf可能被多个线程使用的梦想(太棒了)…我现在要学习未来。也许你可以尝试模式,你只需调用
socket即可。阅读线程1中的一些
,然后检查
error\u code==will\u block
void do_read()
  {
    auto self(shared_from_this());
    socket_.async_read_some(boost::asio::buffer(data_, max_length),
        [this, self](boost::system::error_code ec, std::size_t length)
        {
          if (!ec)
          {
            do_read();
          }
        });
  }