2016-08-10 9 views
6

を考えると、次のテストプログラム:asio 1.11.0スタンドアロンラップが正しくない...またはそれは私ですか?

#include <asio.hpp> 
#include <cassert> 

int main() 
{ 
    asio::io_service ios1, ios2; 
    asio::io_service::strand s2(ios2); 

    auto test_func = wrap(s2, [&] { 
     assert(s2.running_in_this_thread()); 
    }); 

    auto wrap_test_func = wrap(ios1, test_func); 

    wrap_test_func(); 

    ios1.run_one(); 
    ios2.run_one(); 

} 

私の理解では、このプログラムが主張してはならないということです。

wrap_test_funcは、io_serviceios1にラップされています。ラッピングする関数はstrands2ios2を使用)にラップされています。

私が理解しているように、wrap_test_funcdispatch(ios1, test_func)と同じで、s2にラムダを送信する必要があります。

しかし、ラップが内側のラッパーをラップしていないかのように見えます。

これが期待どおりの動作ですか?

+0

私は任意のグローバルラップ機能が見つからないように私は、あなたがこれをコンパイルしたかどうかはわかりませんよ。メンバーレベルのラップを使って、私はアサートが起こっているのを見ることができませんでしたが、 – Arunmu

+0

@Arunmuこれはboost :: asioではありません。それはスタンドアロンのバージョン1.11です。0 –

+0

ええ、私はスタンドアロンバージョン1.11.0(ヘッダーのみ)を使用しています。 'g ++ -std = C++ 11 -DASIO_STANDALONE -wrap_test wrap_test.cc -I/Users/arunmu/asio-master/asio/include /'はどのようにビルドしていますか? – Arunmu

答えて

5

私の誤解だと分かります。

はここでASIOの作者による回答のコピーです:

こんにちはリチャード、

はいこの動作は意図的です。しかし、ネットワーキングTSと では、マスターブランチ上の最新のコードは、 からwrap(期待どおりに別のレイヤーを追加することを意味する)という名前に変更され、 bind_executorに変更されました。この関数は、 関連のエグゼキュータを使用してオブジェクトを単純に埋め込みます。既にそれがあった場合、それはオーバーライドされます。

あなたは真のラッピングが必要な場合は、あなたが明示的に外側の関数オブジェクト(またはラムダ)で、あなたの内 ハンドラをラップし、外 ハンドラ派遣()その「関連するエグゼ」の内のハンドラを持っている必要があります。あなたがあなた自身の非同期操作を書いている として、私は( 「非同期操作上の要件」の一環として、ネットワーキングTSで文書化) 以下のパターンを採用することをお勧め:

  • は、その関連のハンドラを掲載しますget_associated_executorを使用するエグゼキュータ。

  • post()操作がすぐに終了した場合、そのエグゼキュータのハンドラを呼び出します。

  • dispatch()そのexecutorへのハンドラをそれ以外の場合はディスパッチします。

ので(未テストコード、マスターブランチの先端が必要な場合があります):

template<class Task, class Handler> 
    void async_execute(implementation& impl, Task&& task, Handler&& handler) 
    { 
     ... 

     auto ex = asio::get_associated_executor(handler get_io_context()); 

     // this is immediate completion, so we use post() 

     if (not impl) 
     { 
      post(ex, [handler = std::forward<Handler>(handler)]() mutable 
       { 
        promise_type promise; 
        promise.set_exception(std::make_exception_ptr(system_error(errors::null_handle))); 
        handler(promise.get_future()); 
       }); 
      return; 
     } 

     // this is not immediate completion, so we use dispatch() 
     // (NOTE: assumes this->post_execute() does not run the task) 

     // Optional. Really only needed if your io_context participates in the 
     // async operation in some way not shown in this snippet, and not 
     // simply as a channel for delivering the handler. 
     auto io_work = make_work_guard(get_io_contet()); 

     auto handler_work = make_work_guard(ex); 
     auto impl_ptr = impl.get(); 
     auto async_handler = [this, 
           ex, 
           impl_ptr, 
           io_work, handler_work, 
           handler = std::forward<Handler>(handler)] 
     (detail::long_running_task_op::identifier ident, 
     auto future) mutable 
     { 
      assert(impl_ptr); 
      io_work.reset(); 
      dispatch(ex, [handler = std::move(handler), future = std::move(future)]() mutable 
       { 
        handler(std::move(future)); 
       }); 
      assert(impl_ptr); 
      impl_ptr->remove_op(ident); 
     }; 

     ... 

     this->post_execute(); 
    } 

は、この情報がお役に立てば幸いです。

乾杯、クリス

+0

それはもっと複雑になったのだろうか? – Arunmu

+2

@Arunmuはクライアントユーザーの視点からではありません。サービスの実装者(私のような)は、学ぶべき新しいスキルを持っていますが、変更はうまくいきます。特に、ここでやっているのは、先進のハンドラに移動専用のオブジェクトを持ち運ぶことができます。 –

関連する問題