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 ライブラリの正しい動作ですか? そしてもう1つ:それを修正する方法は?mutex関数内で使用する必要send_routineがありますか (または別の解決策があります)?

4

4 に答える 4

6

writeasync_write使用している方法ではスレッドセーフではありません。これにアプローチする標準的な方法は、メッセージをキューに入れ、一度に 1 つずつ書き出すことです。

于 2012-07-20T15:40:42.900 に答える
3

ドキュメント によると、tcp::socket複数のスレッド間で共有されている場合、スレッドセーフではありません。
したがって、提案したように同期を行うか、boost::mutex非同期書き込みを使用します。あなたio_serviceのための仕事。

于 2012-07-20T15:19:47.490 に答える
3

はい、別の解決策があります! ストランド: 明示的なロックなしでスレッドを使用します。ストランドは「イベントハンドラー」のソケットへの「アトミック」アクセスのみを提供することに注意してください。もちろん、コードの場合ではないasio「イベントハンドラー」を使用する必要があります。つまり、boost::asio::write の代わりに boost::asio::async_write を使用する必要があります。

于 2013-07-24T13:19:54.250 に答える
0

2 つの問題が発生する可能性があります。スレッド化の問題は、たとえば、書き込み専用のスレッドを 1 つと、すべてのスレッドがそこに応答をポストするキューを用意することで解決できます。また、設計を非同期のものに変更し、write_some() 関数を使用して、複数のスレッドで実行できる io_service::run() によってスレッド化を行うこともできます。

次に、クライアントが質問に対する回答を同じ順序で期待している場合、プロトコルに問題がある可能性があります。

h番目

トルステン

于 2012-07-20T15:19:41.967 に答える