0

私はboost.asioを使ってサーバーを書いています。接続ごとに読み取りおよび書き込みバッファーがあり、非同期読み取り/書き込み関数 ( async_write_some/ async_read_some) を使用します。

読み込みバッファとがあればasync_read_some問題ありません。async_read_some読み取りバッファは読み取りハンドラーでのみ読み取られるため(通常は同じスレッド内を意味します)、関数を呼び出すだけでかまいません。

ただし、書き込みバッファは複数のスレッドからアクセスする必要があるため、変更のためにロックする必要があります。

最初の質問!

書き込みバッファのロックを回避する方法はありますか?

独自のパケットをスタック バッファーに書き込み、それを書き込みバッファーにコピーします。次に、関数を呼び出しasync_write_someてパケットを送信します。このように 2 つのパケットをシリアルに送信する場合、async_write_some関数を 2 回呼び出しても問題ないでしょうか?

2番目の質問!

ソケットプログラミングにおける非同期書き込みの一般的な方法は何ですか?

読んでくれてありがとう。

4

3 に答える 3

2

申し訳ありませんが、次の 2 つの選択肢があります。

  1. ロックを使用して書き込みステートメントをシリアル化するか、キューから要求を読み取る別のライター スレッドを開始することをお勧めします。他のスレッドは、あまり競合せずにキューに要求を積み重ねることができます (いくつかのミューテックスが必要になります)。

  2. 各書き込みスレッドに独自のソケットを与えてください! これは、ワイヤの反対側のプログラムがサポートできる場合、実際にはより良い解決策です。

于 2009-08-06T07:32:54.507 に答える
1

回答#1:

ロックが実行可能なアプローチであることは正しいですが、これをすべて行うためのはるかに簡単な方法があります。Boostには、ASIOに。と呼ばれる小さな構造がありstrandます。ストランドを使用してラップされたコールバックは、どのスレッドがコールバックを実行するかに関係なく、シリアル化され、保証されます。基本的に、それはあなたのためにどんなロックも処理します。

これは、必要な数のライターを持つことができ、それらがすべて同じストランドでラップされている場合(つまり、すべてのライター間で単一のストランドを共有する場合)、それらはシリアルに実行されることを意味します。注意すべきことの1つは、すべての書き込みを実行するためにメモリ内の同じ実際のバッファを使用しようとしていないことを確認することです。たとえば、これは避けるべきことです:

char buffer_to_write[256];  // shared among threads

/* ... in thread 1 ... */
memcpy(buffer_to_write, packet_1, std::min(sizeof(packet_1), sizeof(buffer_to_write)));
my_socket.async_write_some(boost::asio::buffer(buffer_to_write, sizeof(buffer_to_write)), &my_callback);

/* ... in thread 2 ... */
memcpy(buffer_to_write, packet_2, std::min(sizeof(packet_2), sizeof(buffer_to_write)));
my_socket.async_write_some(boost::asio::buffer(buffer_to_write, sizeof(buffer_to_write)), &my_callback);

そこでは、実際の書き込みバッファ()を共有していますbuffer_to_write。代わりにこのようなことをした場合は、大丈夫です。

/* A utility class that you can use */
class PacketWriter
{
private:
  typedef std::vector<char>  buffer_type;

  static void WriteIsComplete(boost::shared_ptr<buffer_type> op_buffer, const boost::system::error_code& error, std::size_t bytes_transferred)
  {
    // Handle your write completion here
  }

public:
  template<class IO>
  static bool WritePacket(const std::vector<char>& packet_data, IO& asio_object)
  {
    boost::shared_ptr<buffer_type> op_buffer(new buffer_type(packet_data));

    if (!op_buffer)
    {
      return (false);
    }

    asio_object.async_write_some(boost::asio::buffer(*op_buffer), boost::bind(&PacketWriter::WriteIsComplete, op_buffer, boost::asio::placeholder::error, boost::asio::placeholder::bytes_transferred));
  }
};

/* ... in thread 1 ... */
PacketWriter::WritePacket(packet_1, my_socket);

/* ... in thread 2 ... */
PacketWriter::WritePacket(packet_2, my_socket);

ここでは、ストランドをWritePacketに渡した場合にも役立ちます。しかし、あなたはその考えを理解します。

回答#2:

あなたはすでに非常に良いアプローチを取っていると思います。私が提案する1つの提案は、コールバックが呼び出される前にバッファー全体が書き込まれることが保証されるように、async_write代わりに使用することです。async_write_some

于 2009-12-01T17:12:14.150 に答える
0

変更をキューに入れ、書き込みハンドラー内のデータに対して実行できます。

ソケット層が前のデータを送信している間に変更を実行できるように、ネットワークはおそらくパイプの最も遅い部分です (変更に計算コストがかからないと仮定します)。

頻繁に接続/切断する多数のクライアントを処理している場合は、IO 完了ポートまたは同様のメカニズムを調べてください。

于 2009-08-06T08:23:36.183 に答える