하나의 io_service 객체에 복수 boost::asio::deadline_timer
을 사용하고 있습니다. std::shared_ptr
은 boost::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
답장을 보내 주셔서 감사합니다. dead_time_timer의 동작을 이해합니다. 취소 된 상태를 피하고 싶거나 원하는 이유는 제한 시간 핸들러의 deadline_timer가있는 객체에 액세스하기 때문입니다. 이제 타이머 목표 처리기에서 삭제 된 리소스에 액세스하지 않는 방법으로 목표가 변경되었습니다. 그래서 나는 내 질문을 업데이트 (추가)했다. 내 접근 방식을 확인해 주시겠습니까? –
@ TakatoshiKondo 예, 좋습니다. 동시에 발사 할 때 경기 조건을 조심하십시오. – felix
코멘트 주셔서 감사합니다! –