2017-12-01 13 views
1

asio :: ip :: tcp :: socketに一連のネストされた非同期操作があり、できるだけ速く停止させたい他のスレッド。ソケットの今後の非同期操作をキャンセルするか、適切にブロックする

socket->async_something(buffer, CallbackLambdaHeader 
{ 
    if (errorcode) 
    { 
     //exit the sequence 
    } 
    // some code 
    socket->async_something(buffer, CallbackLambdaHeader 
    { 
     if (errorcode) 
     { 
      //exit the sequence 
     } 
     // some code 
     socket->async_something(buffer, CallbackLambdaHeader 
     { 
      if (errorcode) 
      { 
       //exit the sequence 
      } 
      // etc 
     }); 
    }); 
}); 

問題は、単純なsocket->cancel()呼び出しは文句を言わない、常にコールバックのいずれかが実行されてコールの瞬間にために動作することです: は、ここではいくつかの疑似です。したがって、取り消すエンキューされた操作はありませんが、実行中のコールバックはすぐに追加してシーケンスを続行できます。 socket->cancel()の後で非同期操作をキャンセルしたい場合もあります(瞬時にoperation_abortedエラーで完了)。

唯一のアイデアは何とか

//thread1: 
mutex.lock(); 
cancel = true; 
socket->cancel(); 
mutex.unlock(); 

//thread 2: 
mutex.lock(); 
if (!cancel) 
{ 
    socket->async_something(buffer, CallbackLambdaHeader 
    { 
     if (errorcode) 
     { 
      //exit the sequence 
     } 
     // some code 
     mutex.lock(); 
     if (!cancel) 
     { 
      socket->async_something(buffer, CallbackLambdaHeader 
      { 
       if (errorcode) 
       { 
        //exit the sequence 
       } 
       // some code 
       mutex.lock(); 
       if (!cancel) 
       { 
        socket->async_something(buffer, CallbackLambdaHeader 
        { 
         if (errorcode) 
         { 
          //exit the sequence 
         } 
         // etc 
        }); 
       } 
       else 
       { 
        //exit the sequence 
       } 
       mutex.unlock(); 
      }); 
     } 
     else 
     { 
      //exit the sequence 
     } 
     mutex.unlock(); 
    }); 
} 
else 
{ 
    //exit the sequence 
} 
mutex.unlock(); 

mutex.lock()にすべての呼び出しをラップし、解除フラグを使用することです。しかし、それはひどい見えます。
io_service::strandについて聞いたことがありますが、ここでその使い方が分かりません。 socket->cancel()メソッドで.post()を使用しますか?状況{コールバック、キャンセル、コールバック}が不可能であるという保証はありますか?

答えて

0

{コールバック、キャンセル、コールバック}は常に可能です。これは避けたいものではありません。実際には、キャンセルは常にになります。保留中の操作が完了すると、少なくともそれらのコールバックが発生します(操作が中止されたことを示すエラーコードが表示されます)。

あなたはソケットは、「キャンセル」されていた知っていたら、(それをしない操作を取り消す:それは操作、ないソケットをキャンセルする)新しいタスクをスケジュールでを避けるために何をしたい/必要。

私は1つはあなたが望むものをすることができ、状況に応じて2つのもの、見

:あなたはそれをソケットとすべての操作を閉じたい場合は、私は単純に投稿したい永久

  1. をソケットを閉じるタスク(もちろん、保留中の操作もキャンセルされます)。利点は、ソケットの状態[sock.is_open] http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/reference/basic_stream_socket/is_open.htmlをチェックしてから、誤ってそのソケットの新しい操作をスケジュールすることができないことです。

    _service.post([this] { sock.close(); }); 
    

    あなたがサービスを-ning複数のスレッドrunを持っている場合に限っsock変数にアクセスしてデータ競合を回避するためにストランドを必要としています。あなたはソケットopen¹を残し特定の操作チェーンをキャンセルしたい場合は、操作がキャンセルされたときを示す各ソケット、とのフラグを持つことができWhy do I need strand per connection when using boost::asio?

  2. を参照してください。関与

    すべて完了ハンドラははすでにので、そのチェーンに「フォローアップ」の作業を行うことを避けるために、本当に簡単なはずboost::asio::error::operation_abortedを含むerror_codeを受け取ることになります。あなたは、ほとんどのエラーでそれをやりたいかもしれません実際には

    if (ec == boost::asio::error::operation_aborted) 
         return; 
    

    ちょうどコールバックラムダヘッダー内のこのようなものを置きます。

    if (ec) 
         return; // log `ec.message()`? 
    

    フラグがいくつかのスレッドが新しい独立非同期操作(チェーン)を投稿するちょうど約だった場合、単に有利であり、あなたはそれ以外のソリューションを使用して、ソケットを閉じずに、あまりにも(再びことをブロックしたいです#1)。

    sockを共有していない人と共有しないため、そのソケットでは同期は必要ありません。 sockもスレッドセーフではないので、フラグへのアクセスは安全でなければならないことがわかります。

    また、そうでない場合は、まずはストランドが必要でした。

    >

    単一のサービスのスレッドを使用すると、暗黙の鎖を持っていることを意味したが、あなたは決して直接非同期操作を掲示しないことにより、あなたは仕事を掲示多くのスレッドを持っている場合でも煩雑さを避けることができます。

    _service.post([=] { if (!_sock_canceled_flag) _sock.async_something (.... 
          ); }); 
    

    この方法では、すべてのソケット操作が暗黙のストランド上に確実に行われます。


私は実際にこれが意味を作ることができているプロトコルを考えることはできません¹、おそらくデータグラム・プロトコルのため(?)

+0

*「私は単純にタスクを投稿したいですソケットを閉じる "* はい、私は必要なもののように聞こえます。しかし、状況(インストランドコールバックが終了し、データの新しい部分がソケットに到着し、新しいコールバックがストランドにエンキューします。クローズスレッドはclose()メソッドをエンキューできません)。 – Acuion

+0

私は混乱しています。コールバックは、データが到着したときに決して「自発的にエンキュー」しません。読み込み操作は、最初にそのストランドに投稿する必要があります。私は他にあなたが尋ねたいと思うことが分からない。 – sehe

関連する問題