从不同的线程写入boost :: asio socket

qeh*_*hgt 4 c++ sockets multithreading boost boost-asio

在我们的应用程序中,我们使用Boost库(和ASIO进行网络通信).

最近,我们发现如果我们通过相同的套接字从不同的线程发送数据,我们的客户端应用程序就会接收数据.

小测试突出问题:

#include <stdio.h>
#include <boost/thread.hpp>
#include <boost/asio.hpp>

void send_routine(boost::shared_ptr<boost::asio::ip::tcp::socket> s, char c)
{
  std::vector<char> data(15000, c);
  data.push_back('\n');

  for (int i=0; i<1000; i++)
    boost::asio::write(*s, boost::asio::buffer(&data[0], data.size()));
}


int main()
{
  using namespace boost::asio;
  using namespace boost::asio::ip;

  try {
    io_service io_service;
    io_service::work work(io_service);

    const char* host = "localhost";
    const char* service_name = "18000";

    tcp::resolver resolver(io_service);
    tcp::resolver::query query(tcp::v4(), host, service_name);
    tcp::resolver::iterator iterator = resolver.resolve(query);

    auto socket = boost::shared_ptr<tcp::socket>(new tcp::socket(io_service));
    socket->connect(*iterator);

    boost::thread t1(send_routine, socket, 'A');
    boost::thread t2(send_routine, socket, 'B');
    boost::thread t3(send_routine, socket, 'C');

    t1.join();
    t2.join();
    t3.join();
  }
  catch (std::exception& e) {
    printf("FAIL: %s\n", e.what());
  }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

所以,我们在这里创建套接字,连接localhost:18000并启动3个线程,这些线程将写入套接字.

在不同的终端窗口,我运行nc -l -p 18000 | tee out.txt | sort | uniq | wc -l.我期望3作为输出,但它在网络流中返回超过100"不同的字符串"(因此,数据已损坏).但与小缓冲区大小工程(如果我们将改变1500080,例如).

所以,问题是:它是ASIO库的正确行为吗?另一个:如何解决它?我应该mutex在我的send_routine功能中使用(还是有其他解决方案)?

Cha*_*had 5

write并且async_write以您使用它们的方式不是线程安全的.处理此问题的规范方法是对邮件进行排队,然后一次将其写出来.


mka*_*aes 2

根据文档, tcp::socket在多个线程之间共享时不是线程安全的。
因此,您要么按照建议的方式进行同步boost::mutex,要么使用异步写入。适合io_service您的工作。

  • `async_write` 不会神奇地让这个问题消失。不同缓冲区的写入仍然需要串行进行,即使是通过异步 IO 完成也是如此。 (8认同)
  • async_write 由多个 async_send 组成,没有进一步的线程安全性(我研究了实现)。因此,当不同线程使用同一个套接字时,它不是线程安全的。 (2认同)