7

Boost asio チュートリアルのステップ 3 を永久に実行するように調整し、カウンターの代わりに「tick」と「tock」を 1 秒に 1 回表示します。

#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

void print(const boost::system::error_code& /*e*/,
    boost::asio::deadline_timer* t, int* count)
{
    if( !((*count) % 2) )
        std::cout << "tick\n";
    else
        std::cout << "tock\n";

    ++(*count);

    t->expires_at(t->expires_at() + boost::posix_time::seconds(1));
    t->async_wait(boost::bind(print,
          boost::asio::placeholders::error, t, count));
}

int main()
{
  boost::asio::io_service io;

  int count = 0;
  boost::asio::deadline_timer t(io, boost::posix_time::seconds(1));
  t.async_wait(boost::bind(print,
        boost::asio::placeholders::error, &t, &count));

  io.run();

  std::cout << "Final count is " << count << "\n";

  return 0;
}

今、標準入力でキープレスを非同期に処理できるようにしたいと考えています。スリープや待機をブロックせずに、キープレスに応答するために使用できる io_service ハンドラはありますか?

たとえば、次のようなハンドラ関数を実装できるようにしたいと考えています。

void handle_keypress(const boost::error_code&,
    char c)
{
    std::cout << "Tap '" << c << "'\n";
}

そして、このハンドラーの呼び出しは、次のようなものになると思います。

  char c = 0;
  boost::asio::stdin_receiver sr(io);
  st.async_wait(boost::bind(handle_keypress, boost::asio::placeholders::error, &c));

  io.run();

これは、組み込みのサービス ハンドラを使用するか、独自のサービス ハンドラを作成することによって、asio でできることですか?

編集、詳細:

私はこの質問を見てきましたが、受け入れられた回答のリンク先コードは単にこれを次のように行いmainます:

 while (std::cin.getline(

私が作成しているアプリケーションは、上で概説したこの単純なチクタク タップ ギズモではなく、マルチキャスト サーバーになります。いくつかのワーカー スレッドは、パケットをマルチキャスト グループに送信し、メイン スレッドからのメッセージに応答し、メッセージをメイン スレッドに送り返します。次に、アプリケーションは stdin からの入力によって「駆動」されます。たとえば、ユーザーが「P」キーを押すと、マルチキャスト ブロードキャストが一時停止され、「Q」キーを押すと、すべてがシャットダウンします。 . メイン スレッドでは、これらの入力に応答してワーカー スレッドにメッセージを送信するだけです。

上記のwhileループは、ユーザーからの stdin 入力を待機している間、メイン スレッドがワーカー スレッドからのメッセージを処理できないため、私のシナリオでは機能しません。ワーカー スレッドからのこれらのメッセージの一部は、stdout への出力を生成します。

4

3 に答える 3

5

posix チャット クライアントが while ループまたは invokes を使用しているとは思いませんstd::getline。これは、以前の回答でリンクしたサンプル コードです。おそらく、あなたは別の例を参照していますか?io_service::dispatchいずれにせよ、別のスレッドを使用する必要はありません。ここでは、ストリーム記述子の組み込み機能が問題なく機能します。同様の質問に対する私の以前の回答を参照してください: a を使用してそれposix::stream_descriptorに割り当てSTDIN_FILENOます。async_read読み取りハンドラーで要求を使用して処理します。

これを実現する 1 つの方法でサンプル コードを修正しました

#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

void print(const boost::system::error_code& /*e*/,
    boost::asio::deadline_timer* t, int* count)
{
    if( !((*count) % 2) )
        std::cout << "tick\n";
    else
        std::cout << "tock\n";

    ++(*count);

    t->expires_at(t->expires_at() + boost::posix_time::seconds(1));
    t->async_wait(boost::bind(print,
          boost::asio::placeholders::error, t, count));
}

class Input : public boost::enable_shared_from_this<Input>
{
public:
    typedef boost::shared_ptr<Input> Ptr;

public:
    static void create(
            boost::asio::io_service& io_service
            )
    {
        Ptr input(
                new Input( io_service )
                );
        input->read();
    }

private:
    explicit Input(
            boost::asio::io_service& io_service
         ) :
        _input( io_service )
    {
        _input.assign( STDIN_FILENO );
    }

    void read()
    {
        boost::asio::async_read(
                _input,
                boost::asio::buffer( &_command, sizeof(_command) ),
                boost::bind(
                    &Input::read_handler,
                    shared_from_this(),
                    boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred
                    )
                );
    }

    void read_handler(
            const boost::system::error_code& error,
            const size_t bytes_transferred
            )
    {
        if ( error ) {
            std::cerr << "read error: " << boost::system::system_error(error).what() << std::endl;
            return;
        }

        if ( _command != '\n' ) {
            std::cout << "command: " << _command << std::endl;
        }

        this->read();
    }

private:
    boost::asio::posix::stream_descriptor _input;
    char _command;
};

int main()
{
  boost::asio::io_service io;

  int count = 0;
  boost::asio::deadline_timer t(io, boost::posix_time::seconds(1));
  t.async_wait(boost::bind(print,
        boost::asio::placeholders::error, &t, &count));

  Input::create( io);

  io.run();

  std::cout << "Final count is " << count << "\n";

  return 0;
}

コンパイル、リンク、および実行

samm:stackoverflow samm$ g++ -I /opt/local/include stdin.cc -L /opt/local/lib -lboost_system -Wl,-rpath,/opt/local/lib
samm:stackoverflow samm$ echo "hello world" | ./a.out
command: h
command: e
command: l
command: l
command: o
command:  
command: w
command: o
command: r
command: l
command: d
read error: End of file
tick
tock
tick
tock
tick
tock
tick
tock
tick
tock
^C
samm:stackoverflow samm$
于 2012-06-12T03:12:27.363 に答える
2

stdin を別のスレッドで処理し、キー押下をio_service::dispatch経由でメイン イベント ループにポストするオプションが常にあります。

この関数は、io_service に特定のハンドラーの実行を要求するために使用されます。

io_service は、run()、run_one()、poll()、または poll_one() メンバー関数が現在呼び出されているスレッドでのみハンドラーが呼び出されることを保証します。

于 2012-06-07T21:28:07.953 に答える