2017-03-27 1 views
0

하나의 io_service 객체에 복수 boost::asio::deadline_timer을 사용하고 있습니다. std::shared_ptrboost::asio::deadline_timer이고 인덱스가있는 std::map<int, std::shared_ptr<debug_tim>> timers 컨테이너에 저장됩니다.이미 파괴 된 발사를 피하는 방법 boost :: asio :: deadline_timer

타이머 처리기에서 다른 boost::asio::deadline_timer을 지 웁니다. 그러나 지워지는 timer woule은 종종 성공 오류 코드로 해고되는 것으로 보입니다.

이를 방지 할 수있는 방법이 있습니까? 타이머 처리기가 지워진 boost::asio::deadline_timer에 해당하는 것은 항상 Operation canceled과 함께 발생합니다.

내가 누락 된 항목이 있습니까? 여기

는 동작

https://wandbox.org/permlink/G0qzYcqauxdqw4i7

#include <iostream> 
#include <memory> 

#include <boost/asio.hpp> 

// deadline_timer with index ctor/dtor print 
struct debug_tim : boost::asio::deadline_timer { 
    debug_tim(boost::asio::io_service& ios, int i) : boost::asio::deadline_timer(ios), i(i) { 
     std::cout << "debug_tim() " << i << std::endl; 
    } 
    ~debug_tim() { 
     std::cout << "~debug_tim() " << i << std::endl; 
    } 
    int i; 
}; 

int main() { 
    boost::asio::io_service ios; 
    std::map<int, std::shared_ptr<debug_tim>> timers; 
    { 
     for (int i = 0; i != 5; ++i) { 
      auto tim = std::make_shared<debug_tim>(ios, i); 
      std::cout << "set timer " << i << std::endl; 
      tim->expires_from_now(boost::posix_time::seconds(1)); 
      timers.emplace(i, tim); 
      tim->async_wait([&timers, i](auto ec){ 
        std::cout << "timer fired " << i << " : " << ec.message() << std::endl; 
        auto it = timers.find(i); 
        if (it == timers.end()) { 
         std::cout << " already destructed." << std::endl; 
        } 
        else { 
         int other_idx = i + 1; // erase other timer (e.g. i + 1) 
         timers.erase(other_idx); 
         std::cout << " erased " << other_idx << std::endl; 
        } 
       } 
      ); 
     } 
    } 
    ios.run(); 
} 

내가 타이머를 삭제하기 전에 나는 또한 boost::asio::deadline_timer::cancel() 전화를 재현 코드입니다. 그러나 비슷한 결과가 나옵니다. 여기에 취소 버전 :

https://wandbox.org/permlink/uM0yMFufkyn9ipdG

#include <iostream> 
#include <memory> 

#include <boost/asio.hpp> 

// deadline_timer with index ctor/dtor print 
struct debug_tim : boost::asio::deadline_timer { 
    debug_tim(boost::asio::io_service& ios, int i) : boost::asio::deadline_timer(ios), i(i) { 
     std::cout << "debug_tim() " << i << std::endl; 
    } 
    ~debug_tim() { 
     std::cout << "~debug_tim() " << i << std::endl; 
    } 
    int i; 
}; 

int main() { 
    boost::asio::io_service ios; 
    std::map<int, std::shared_ptr<debug_tim>> timers; 
    { 
     for (int i = 0; i != 5; ++i) { 
      auto tim = std::make_shared<debug_tim>(ios, i); 
      std::cout << "set timer " << i << std::endl; 
      tim->expires_from_now(boost::posix_time::seconds(1)); 
      timers.emplace(i, tim); 
      tim->async_wait([&timers, i](auto ec){ 
        std::cout << "timer fired " << i << " : " << ec.message() << std::endl; 
        auto it = timers.find(i); 
        if (it == timers.end()) { 
         std::cout << " already destructed." << std::endl; 
        } 
        else { 
         int other_idx = i + 1; // erase other timer (e.g. i + 1) 
         auto other_it = timers.find(other_idx); 
         if (other_it != timers.end()) { 
          other_it->second->cancel(); 
          timers.erase(other_it); 
         } 
         std::cout << " erased " << other_idx << std::endl; 
        } 
       } 
      ); 
     } 
    } 
    ios.run(); 
} 

편집

펠릭스는 대답 주셔서 감사합니다. boost::asio::deadline::timer::cancel() 동작을 이해합니다. 나는 항상 평생 걱정해야합니다 boost::asio::deadline::timer. 내 프로젝트의 실제 코드 인`boost :: asio :: deadline :: timer`는 세션 객체 같은 다른 객체의 멤버 변수입니다. 그리고 타이머 핸들러에서 객체에 액세스합니다. 이건 위험 해.

안전한 코드를 작성하는 방법을 고려합니다. 그리고 객체의 수명을 확인하기 위해 std::weak_ptr을 사용합니다.

#include <iostream> 
#include <memory> 

#include <boost/asio.hpp> 

// deadline_timer with index ctor/dtor print 
struct debug_tim : boost::asio::deadline_timer { 
    debug_tim(boost::asio::io_service& ios, int i) : boost::asio::deadline_timer(ios), i(i) { 
     std::cout << "debug_tim() " << i << std::endl; 
    } 
    ~debug_tim() { 
     std::cout << "~debug_tim() " << i << std::endl; 
    } 
    int i; 
}; 

int main() { 
    boost::asio::io_service ios; 
    std::map<int, std::shared_ptr<debug_tim>> timers; 
    { 
     for (int i = 0; i != 5; ++i) { 
      auto tim = std::make_shared<debug_tim>(ios, i); 
      std::cout << "set timer " << i << std::endl; 
      tim->expires_from_now(boost::posix_time::seconds(1)); 
      timers.emplace(i, tim); 

      // Capture tim as the weak_ptr wp 
      tim->async_wait([&timers, i, wp = std::weak_ptr<debug_tim>(tim)](auto ec){ 
        std::cout << "timer fired " << i << " : " << ec.message() << std::endl; 

        // Check the lifetime of wp 
        if (!wp.lock()) std::cout << " timer freed." << std::endl; // return here on actual code 

        auto it = timers.find(i); 
        if (it == timers.end()) { 
         std::cout << " already destructed." << std::endl; 
        } 
        else { 
         int other_idx = i + 1; // erase other timer (e.g. i + 1) 
         timers.erase(other_idx); 
         std::cout << " erased " << other_idx << std::endl; 
        } 
       } 
      ); 
     } 
    } 
    ios.run(); 
} 

이이 boost::asio::deadline_timer이있는 삭제 된 개체에 액세스하는 피할 수있는 좋은 방법은 다음과 같습니다

여기

업데이트 된 코드?

편집

내 weak_ptr를 솔루션은 잘 작동합니다.

reference of deadline_timer::cancel에 따르면 How to avoid firing already destroyed boost::asio::deadline_timer

답변

1

를 참조하십시오 : 타이머가 이미 호출 될 때 취소() 만료 된 경우

비동기 대기 작업 후 처리기를 것입니다 :

  • 이 이미 호출되었습니다. 또는

  • 은 가까운 시일 내에 호출 대기 중입니다.

이 핸들러를 더 이상 취소 할 수 없으므로 대기 조작이 성공적으로 완료되었음을 나타내는 오류 코드가 전달됩니다.

cancel()을 호출해도 이미 대기열에 대기중인 타이머를 취소 할 수 없습니다.

그리고 dealin_timer가 소멸자를 대체하지 않는 것으로 보입니다. (deadline_timer의 멤버 목록에는 소멸자가 없습니다.)

코드 스 니펫에서 모든 타이머는 거의 동시에 실행됩니다. asio가 내부 쓰레드를 사용할 것이라는 점에 관해서는, 하나의 완성 핸들러가 호출 될 때 다른 핸들러가 큐에 저장 될 가능성이 매우 높습니다.

+0

답장을 보내 주셔서 감사합니다. dead_time_timer의 동작을 이해합니다. 취소 된 상태를 피하고 싶거나 원하는 이유는 제한 시간 핸들러의 deadline_timer가있는 객체에 액세스하기 때문입니다. 이제 타이머 목표 처리기에서 삭제 된 리소스에 액세스하지 않는 방법으로 목표가 변경되었습니다. 그래서 나는 내 질문을 업데이트 (추가)했다. 내 접근 방식을 확인해 주시겠습니까? –

+0

@ TakatoshiKondo 예, 좋습니다. 동시에 발사 할 때 경기 조건을 조심하십시오. – felix

+0

코멘트 주셔서 감사합니다! –