2011-08-08 23 views
1

私はBoost :: asioとasync_readを使用して、シリアルポートを使用するプロトコルでタイムアウトを実装しようとしています。Boost :: asioとasync_read

同期読み取りを使用してテスト実装を行っていますが、これは単なるfindで動作しますが、タイムアウトを伴う実装は機能しません。

void set_result(boost::optional<boost::system::error_code> * a, boost::system::error_code b) { 
    a->reset(b); 
} 

void receive(boost::asio::io_service & io, boost::asio::serial_port & cctalk_port, boost::asio::streambuf & result){ 
#if 1 
    // Non-working implementation with timeout 
    boost::optional<boost::system::error_code> timer_result; 
    boost::optional<boost::system::error_code> read_result; 

    boost::asio::deadline_timer timer(io); 
    LOG(INFO) << "Timer at 5000ms starts here"; 
    timer.expires_from_now(boost::posix_time::milliseconds(5000)); // allow up to 50ms of timeout for every char 
    timer.async_wait(boost::bind(&set_result, &timer_result, _1)); 

    LOG(INFO) << "Async read starts here (result.size() == " << result.size() << ")"; 
    boost::asio::async_read(
      cctalk_port, 
      result, 
      boost::asio::transfer_at_least(1), 
      boost::bind(&set_result, &read_result, _1)); 
    boost::system::error_code ec; 

    while(1) { 
     io.poll_one(ec); 

     if(ec != 0 || read_result != 0 || timer_result != 0) 
      LOG(INFO) << "Error code: " << ec << " read_result: " << read_result << " timer_result: " << timer_result; 

     if (read_result) { 
      timer.cancel(); 
      LOG(INFO) << "Result ready (" << result.size() << ")"; 
      return; 

     } else if (timer_result) { 
      LOG(INFO) << "Timeout"; 
      throw runtime_error("timeout"); 
     } 
    } 

    LOG(INFO) << "Not suppose to happen"; 

#else 
    // Working implementation without timeout 
    boost::asio::read(cctalk_port, result, boost::asio::transfer_at_least(1)); 
#endif 
} 

void receive(boost::asio::io_service & io, boost::asio::serial_port & cctalk_port, size_t size, boost::asio::streambuf & result){ 
    LOG(INFO) << "Fetch at least " << size << " has allready: " << result.size(); 
    while(result.size() < size) { 
     receive(io, cctalk_port, result); 
     LOG(INFO) << "Buffer size: " << result.size() << "/" << size; 
    } 
} 

私は、次の出力を得、このコードを実行します。

I0808 17:25:40.809615 3682 ccTalkScan.cxx:137] Fetch at least 5 has allready: 0 
I0808 17:25:40.809672 3682 ccTalkScan.cxx:99] Timer at 5000ms starts here 
I0808 17:25:40.809686 3682 ccTalkScan.cxx:103] Async read starts here (result.size() == 0) 
I0808 17:25:40.809731 3682 ccTalkScan.cxx:115] Error code: system:0 read_result: 1 timer_result: 0 
I0808 17:25:40.809738 3682 ccTalkScan.cxx:119] Result ready (12) 
I0808 17:25:40.809742 3682 ccTalkScan.cxx:140] Buffer size: 12/5 
I0808 17:25:40.809778 3682 ccTalkScan.cxx:137] Fetch at least 5 has allready: 7 
I0808 17:25:40.809783 3682 ccTalkScan.cxx:137] Fetch at least 9 has allready: 7 
I0808 17:25:40.809788 3682 ccTalkScan.cxx:99] Timer at 5000ms starts here 
I0808 17:25:40.809797 3682 ccTalkScan.cxx:103] Async read starts here (result.size() == 7) 
I0808 17:25:40.809808 3682 ccTalkScan.cxx:115] Error code: system:0 read_result: 0 timer_result: 1 
I0808 17:25:40.809811 3682 ccTalkScan.cxx:123] Timeout 

それは出力から明らかなように、タイマーが必要速く5000msよりも、1ミリ秒未満この場合、設定されています。

さらに、私が受け取る実際のバイトを見ると、最初のバイトがないようです。

答えて

6

Hmm ...ここでの問題は、基本的に前のタイマーをキャンセルするときに微妙です。io_service(そのタイマーを担当するハンドラの呼び出し)で別のイベントがトリガされ、キャンセルされたことを示しますエラーコード)。 poll_oneにしかコールしていないので、読んで読んでもいいので、読み込みを処理してから、io_serviceで後続のイベントを設定するタイマーをキャンセルします(この実行では呼び出されません)。 メソッドが2回目に呼び出され、poll_oneに電話すると、このイベントがトリガーされます(また、set_resultメソッドでエラー状態がチェックされないため)、オプションの状態は良好です(エラーが含まれています)。これをタイムアウトとして扱います...

フォローですか?

+0

私はあなたの要点を見ていますが、私にとっては、チャンスを与えられたタイマーがイベントをトリガーするのは奇妙なようです。しかし、どのように問題を解決することを提案しますか? – Allan

+0

- これは別の質問です。 ;)これを解決する最も簡単な方法は、error_codeが取り消された場合にオプションを設定しないtimerに対して異なる 'set_result'を持たせることです。 – Nim

+0

さて、あなたは正しいと思いますが、何か間違っているようです。 – Allan

関連する問題