2012-04-15 9 views
6

実行中のタイマーでexpires_from_now()に電話すると、 タイマーがキャンセルされ、新しいタイマーが呼び出されます。 関連するハンドラが呼び出されます。 キャンセルタイマーと期限切れタイマーの間のハンドラ を区別することは容易です。 しかし、期限切れのタイマーと再トリガーされたタイマーの間で を区別する方法があれば、私は疑問に思います。 どちらの場合も、ハンドラはエラーコードoperation_abortedで と呼ばれます。 または、私はいくつかの詳細が欠落しているかもしれません。再突入ブーストからのキャンセルをどのように区別しますか?

次のコードは、次のような出力を生成します。

20120415 21:32:28079507 Main: Timer1 set to 15 s.  
20120415 21:32:28079798 Main: Timer1 set to 12 s.  
20120415 21:32:28079916 Handler1: Timer 1 was cancelled or retriggered.  
20120415 21:32:40079860 Handler1: expired. 

これはタイマーを再トリガすると、同じハンドラを呼び出すことにより、同じことを実行しますので、ハンドラは、キャンセルハンドラの アクションを実装することができないことを示唆しています行動。これは意図した動作ではない可能性があります。

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

using namespace boost::posix_time; 
using namespace std; 

void handler1(const boost::system::error_code &ec) 
{ 
    if (ec == boost::asio::error::operation_aborted) 
    { 
     cout << microsec_clock::local_time() << " Handler1: Timer was cancelled or retriggered." << endl; 
    } 
    else 
    { 
     cout << microsec_clock::local_time() << " Handler1: Timer expired." << endl; 
    } 
} 

boost::asio::io_service io_service1; 

void run1() 
{ 
    io_service1.run(); 
} 

int main() 
{ 
    time_facet *facet = new time_facet("%Y%m%d %H:%M:%S%f"); 
    cout.imbue(locale(cout.getloc(), facet)); 

    boost::asio::deadline_timer timer1(io_service1, seconds(15)); 
    timer1.async_wait(handler1); 
    cout << microsec_clock::local_time() << " Main: Timer1 set to 15 s." << endl; 
    // now actually run the timer 
    boost::thread thread1(run1); 
    timer1.expires_from_now(seconds(12)); 
    cout << microsec_clock::local_time() << " Main: Timer1 set to 12 s." << endl; 
    // here the timer is running, but we need to reset the deadline 
    timer1.async_wait(handler1); 
    thread1.join(); // wait for thread1 to terminate 
} 
+1

、あなたが達成したいかを教えてください。より大きな写真は何ですか? –

+0

私はいくつかのイベントトリガーターンオン遅延を実装しようとしています。私はそれを再トリガーせずに基本的なターンオン遅延を実装することができます。しかし、あなたが可変または変化する時間遅延を受け入れるならば、それを再トリガーする必要があります。 –

+0

そして、何もしないでください。あなたはoperation_abortedを取得し、与えられたハンドラを覚えて、再度設定しますか? –

答えて

4

ラッパーを作成するクラスを作成することをお勧めします。deadline_timerを使用してください。キャンセルするときは、キャンセルされたことを覚えておくフラグを設定します。ハンドラで、フラグをリセットします。 expires_from_now()を呼び出すときにフラグを設定しないでください。

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

class Timer 
{ 
public: 
    Timer(
      const std::string& name, 
      boost::asio::io_service& io_service 
     ) : 
     _name(name), 
     _timer(io_service), 
     _cancelled(false) 
    { 
     _timer.expires_from_now(boost::posix_time::seconds(0)); 
     this->wait(); 
    } 

    void wait() 
    { 
     _timer.async_wait(
       boost::bind(
        &Timer::handler, 
        this, 
        boost::asio::placeholders::error 
        ) 
       ); 
    } 

    void cancel() { 
     _cancelled = true; 
     _timer.cancel(); 
    } 

    void restart() { 
     _timer.expires_from_now(boost::posix_time::seconds(5)); 
    } 

private: 
    void handler(
      const boost::system::error_code& error 
      ) 
    { 
     if (!error) { 
      std::cout << _name << " " << __FUNCTION__ << std::endl; 
      _timer.expires_from_now(boost::posix_time::seconds(5)); 
      this->wait(); 
     } else if (error == boost::asio::error::operation_aborted && _cancelled) { 
      _cancelled = false; 
      std::cout << _name << " " << __FUNCTION__ << " cancelled" << std::endl; 
     } else if (error == boost::asio::error::operation_aborted) { 
      std::cout << _name << " " << __FUNCTION__ << " retriggered" << std::endl; 
      this->wait(); 
     } else { 
      std::cout << "other error: " << boost::system::system_error(error).what() << std::endl; 
     } 
    } 

private: 
    const std::string _name; 
    boost::asio::deadline_timer _timer; 
    bool _cancelled; 
}; 

int 
main() 
{ 
    boost::asio::io_service ios; 
    Timer timer1("timer1", ios); 
    Timer timer2("timer2", ios); 

    boost::thread thread(
      boost::bind(
       &boost::asio::io_service::run, 
       boost::ref(ios) 
       ) 
      ); 

    sleep(3); 
    std::cout << "cancelling" << std::endl; 
    timer1.cancel(); 
    timer2.restart(); 

    thread.join(); 
} 

サンプルセッション

macmini:stackoverflow samm$ ./a.out 
timer1 handler 
timer2 handler 
cancelling 
timer1 handler cancelled 
timer2 handler retriggered 
timer2 handler 
^C 
macmini:stackoverflow samm$ 
0

私はどのような方法を知らないと、おそらくそれを行うには良い方法はありませんが(あなたがこれらの二つの状況離れて伝えることができるというドキュメントには何もありません)。

私はこれが目的によって行われたと信じています。時にはとき、したがって、正確に何が起こるかを伝えるのは難しいだろう、何かがすでにタイマーで待っていたか伝えるのは難しいです

  • :ので、新しい有効期限の時刻にdeadline_timerを設定すると、以前のハンドラをcancellsあなたは有効期限を設定します。
  • これは、スケジュールされたイベントが2回実行されないようにする簡単な方法です。特別な方法で別のエラーコードを処理する必要があると、エラーが発生しやすくなります。
関連する問題