ホームページ > バックエンド開発 > C++ > Boost Asio でインターリーブされた `async_write` 呼び出しを防ぐ方法は?

Boost Asio でインターリーブされた `async_write` 呼び出しを防ぐ方法は?

Linda Hamilton
リリース: 2024-11-28 01:55:10
オリジナル
972 人が閲覧しました

How to Prevent Interleaved `async_write` Calls in Boost Asio?

Boost Asio での async_write 呼び出しのインターリーブを防ぐ方法

分散システムでは、クライアントがサーバーにメッセージを非同期に送信するのが一般的です。受信メッセージを処理するために、サーバーは通常、メッセージが受信順に順次処理されるキューベースのメカニズムを実装します。ただし、特定のシナリオでは、メッセージがインターリーブされ、予期しない動作が発生する可能性があります。

問題の説明

複数のクライアントからメッセージを同時に受信するサーバーが関係するシナリオを考えてみましょう。各クライアントのメッセージは、async_write を使用して非同期的に処理されます。クライアントが速いペースでメッセージを送信する場合、async_write 呼び出しがインターリーブされ、メッセージが順番どおりに処理されない可能性があります。

解決策: キューベースのアプローチ

これを防ぐにはasync_write 呼び出しのインターリーブでは、キューベースのアプローチを採用できます。その仕組みは次のとおりです。

  1. 各クライアントには専用の送信メッセージ キューがあります。
  2. クライアントがメッセージを送信すると、メッセージは送信キューに追加されます。
  3. サーバーは各クライアントの送信キューのサイズをチェックします。
  4. キューが空でない場合、サーバーはキューを開始します。 async_write オペレーションは、キュー内の最初のメッセージを送信します。
  5. async_write オペレーションが完了すると、サーバーはキューを再度チェックします。
  6. キュー内にさらにメッセージがある場合は、別の async_write オペレーションが実行されます。
  7. このプロセスは、キュー内のすべてのメッセージが送信されるまで繰り返されます。

実装例

次のコード スニペットは、このキューベースのアプローチを実装する方法を示しています。

// Include necessary headers
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <deque>
#include <iostream>
#include <string>

class Connection
{
public:
    Connection(
            boost::asio::io_service&amp; io_service
            ) :
        _io_service( io_service ),
        _strand( _io_service ),
        _socket( _io_service ),
        _outbox()
    {

    }

    void write( 
            const std::string&amp; message
            )
    {
        _strand.post(
                boost::bind(
                    &amp;Connection::writeImpl,
                    this,
                    message
                    )
                );
    }

private:
    void writeImpl(
            const std::string&amp; message
            )
    {
        _outbox.push_back( message );
        if ( _outbox.size() > 1 ) {
            // outstanding async_write
            return;
        }

        this->write();
    }

    void write()
    {
        const std::string&amp; message = _outbox[0];
        boost::asio::async_write(
                _socket,
                boost::asio::buffer( message.c_str(), message.size() ),
                _strand.wrap(
                    boost::bind(
                        &amp;Connection::writeHandler,
                        this,
                        boost::asio::placeholders::error,
                        boost::asio::placeholders::bytes_transferred
                        )
                    )
                );
    }

    void writeHandler(
            const boost::system::error_code&amp; error,
            const size_t bytesTransferred
            )
    {
        _outbox.pop_front();

        if ( error ) {
            std::cerr << "could not write: " << boost::system::system_error(error).what() << std::endl;
            return;
        }

        if ( !_outbox.empty() ) {
            // more messages to send
            this->write();
        }
    }


private:
    typedef std::deque<std::string> Outbox;

private:
    boost::asio::io_service&amp; _io_service;
    boost::asio::io_service::strand _strand;
    boost::asio::ip::tcp::socket _socket;
    Outbox _outbox;
};

int
main()
{
    boost::asio::io_service io_service;
    Connection foo( io_service );
}
ログイン後にコピー

結論

キューベースのアプローチを実装すると、async_write 呼び出しのインターリーブを効果的に防止でき、メッセージが正しい順序で処理されることが保証されます。これは、メッセージ処理の順序がシステムの全体的な機能に大きな影響を与えるシナリオでは特に重要です。

以上がBoost Asio でインターリーブされた `async_write` 呼び出しを防ぐ方法は?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート