5

在我们的应用程序中,我们使用 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;
}

因此,我们在这里创建套接字,连接localhost:18000并启动 3 个将写入套接字的线程。

在不同的终端窗口中,我运行nc -l -p 18000 | tee out.txt | sort | uniq | wc -l. 我希望3作为输出,但它在网络流中返回超过 100 个“不同的字符串”(因此,数据已损坏)。但它适用于较小的缓冲区大小(例如,如果我们将更15000改为80)。

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

4

4 回答 4

6

write并且async_write在您使用它们的方式上不是线程安全的。解决此问题的规范方法是将您的消息排队,然后一次写出一条。

于 2012-07-20T15:40:42.900 回答
3

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

于 2012-07-20T15:19:47.490 回答
3

是的,还有另一种解决方案! Strands:使用没有显式锁定的线程。请注意,strands 只为“事件处理程序”提供对套接字的“原子”访问,当然您需要使用 asio“事件处理程序”,这不是您的代码的情况。换句话说,您需要使用 boost::asio::async_write 而不是 boost::asio::write。

于 2013-07-24T13:19:54.250 回答
0

您可能有两个问题,线程问题可以通过例如有一个专用于写入的线程和一个所有线程发布响应的队列来解决。您还可以将您的设计更改为异步设计并使用 write_some() 函数并让线程由 io_service::run() 完成,它可以由多个线程运行。

其次,如果客户希望以相同的顺序回答问题,您可能会遇到协议问题。

hth

托尔斯滕

于 2012-07-20T15:19:41.967 回答