4

Boost ASIOの使い方を学んでいます。以下は、Boost ASIO のドキュメントと一緒に提供されたチャットの例からコピーされたコードです。

typedef std::deque<chat_message> chat_message_queue;

class chat_client
{
    public:
        chat_client(boost::asio::io_service& io_service,
                tcp::resolver::iterator endpoint_iterator)
            : io_service_(io_service),
            socket_(io_service)
    {
        boost::asio::async_connect(socket_, endpoint_iterator,
                boost::bind(&chat_client::handle_connect, this,
                    boost::asio::placeholders::error));
    }

        void write(const chat_message& msg)
        {
            io_service_.post(boost::bind(&chat_client::do_write, this, msg));
        }

        void close()
        {
            io_service_.post(boost::bind(&chat_client::do_close, this));
        }

    private:

        void handle_connect(const boost::system::error_code& error)
        {
            //Implementation
        }

        void handle_read_header(const boost::system::error_code& error)
        {
            //Implementation
        }

        void handle_read_body(const boost::system::error_code& error)
        {
            //Implementation
        }

        void do_write(chat_message msg)
        {
            bool write_in_progress = !write_msgs_.empty();
            write_msgs_.push_back(msg);
            if (!write_in_progress)
            {
                boost::asio::async_write(socket_,
                        boost::asio::buffer(write_msgs_.front().data(),
                            write_msgs_.front().length()),
                        boost::bind(&chat_client::handle_write, this,
                            boost::asio::placeholders::error));
            }
        }



        void handle_write(const boost::system::error_code& error)
        {
            //Implementation
        }

        void do_close()
        {
            socket_.close();
        }

    private:
        boost::asio::io_service& io_service_;
        tcp::socket socket_;
        chat_message read_msg_;
        chat_message_queue write_msgs_;
};
  1. 書き込みは非同期であり、メンバー変数write_msgs_read_msgs_. ここで同時実行性に問題があるべきではありませんか?

  2. postを実行するスレッドからを呼び出しても安全ですio_service::run?dispatch? 実行されていないスレッドから同じ呼び出しを行うのはどうio_service::runですか?

  3. ではdoSend()、メッセージをwrite_msgs_直接送信するのではなく、 にプッシュするのはなぜですか? また、同じ関数で、write_msgs_が空であるかどうかをチェックし、そうでない場合にのみ送信に進むのはなぜですか? write_msgs_.empty() = false書き込みが行われているということですか?どのように?

  4. 1 つのスレッドでのみ呼び出される場合do_write()、送信シーケンスを維持するためにキューが必要なのはなぜですか? io_service手元のタスクを終了してから、によって呼び出された非同期操作を実行しませんdo_writeか? dispatch代わりにa を使用するpostと、上記の例に違いが生じますか?

4

1 に答える 1

8
  1. 書き込みは非同期ですが、ここにはマルチスレッドはありませんdo_write()。1 つのスレッドで呼び出されます。もちろん、送信されるバッファは、完了ハンドラが呼び出されるまで、生きていて変更されていない必要があります。

  2. post() と dispatch() はどのスレッドからでも安全に呼び出すことができます。io_service ドキュメントの「スレッド セーフ」セクションを読んでください。

  3. async_writeが進行中で、同じソケットで再度呼び出した場合、async_writeデータが送信される順序は未定義です。つまり、データがめちゃくちゃになります。これを回避する最も簡単な方法は、メッセージのキューを作成することasync_writeですasync_write。(ちなみに も同様です。)書き込みが行われているというのはasync_readなぜですか? 空でないwrite_msgs_.empty() = false限り、 (前の の完了ハンドラー) は別の を発行します。が空の場合、このループは中断されます。write_msgs_handle_writeasync_writeasync_writewrite_msgs_

  4. async_write に関するドキュメントの内容をお読みください。

    この操作は、ストリームの async_write_some 関数への 0 回以上の呼び出しに関して実装され、構成操作として知られています。プログラムは、この操作が完了するまで、ストリームが他の書き込み操作 (async_write、ストリームの async_write_some 関数、または書き込みを実行するその他の合成操作など) を実行しないようにする必要があります。

dispatchvsについてpostは、私が見る限り、上記の例では交換可能です。ポストされるファンクターを同期的に呼び出したくない場合は、ポストの使用が不可欠です。

于 2012-07-18T08:23:21.763 に答える