gpt4 book ai didi

c++ - 如何防止截止时间计时器调用已删除类中的函数?

转载 作者:可可西里 更新时间:2023-11-01 18:29:36 26 4
gpt4 key购买 nike

我在一段真实代码中遇到问题,其中属于已删除类的函数被 boost::asio::deadline_timer 调用,偶尔会导致段错误。

我遇到的问题是 deadline_timer 的删除是从同一 io_service 上的另一个计时器运行的。删除第一个 deadline_timer 将触发对要运行的函数的最终调用,并出现 boost::asio::error::operation_aborted 错误。然而,这只能在删除完成后安排在(相同的)io_service 上,但到那时对象已经被删除,因此不再有效。

所以我的问题是:如何防止这种情况发生?

以下是同样故障的简化示例:

//============================================================================
// Name : aTimeToKill.cpp
// Author : Pelle
// Description : Delete an object using a timer, from a timer
//============================================================================

#include <iostream>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/thread.hpp>

using namespace std;
using namespace boost;

struct TimeBomb
{
bool m_active;
asio::deadline_timer m_runTimer;

TimeBomb(boost::asio::io_service& ioService)
: m_active(true)
, m_runTimer(ioService)
{
cout << "Bomb placed @"<< hex << (int)this << endl;
m_runTimer.expires_from_now(boost::posix_time::millisec(1000));
m_runTimer.async_wait(boost::bind(&TimeBomb::executeStepFunction, this, _1));
}

~TimeBomb()
{
m_active = false;
m_runTimer.cancel();
cout << "Bomb defused @"<< hex << (int)this << endl;
}

void executeStepFunction(const boost::system::error_code& error)
{
// Canceled timer
if (error == boost::asio::error::operation_aborted)
{
std::cout << "Timer aborted: " << error.message() << " @" << std::hex << (int)this << std::endl;
return;
}
if (m_active)
{
// Schedule next step
cout << "tick .." <<endl;
m_runTimer.expires_from_now(
boost::posix_time::millisec(1000));
m_runTimer.async_wait(boost::bind(&TimeBomb::executeStepFunction, this, _1));
}
}
};

struct BomberMan
{
asio::deadline_timer m_selfDestructTimer;
TimeBomb* myBomb;

BomberMan(boost::asio::io_service& ioService)
: m_selfDestructTimer(ioService)
{
cout << "BomberMan ready " << endl;
myBomb = new TimeBomb(ioService);
m_selfDestructTimer.expires_from_now(boost::posix_time::millisec(10500));
m_selfDestructTimer.async_wait(boost::bind(&BomberMan::defuseBomb, this, _1));
}

void defuseBomb(const boost::system::error_code& error)
{
cout << "Defusing TimeBomb" << endl;
delete myBomb;
}
};


int main()
{
boost::asio::io_service m_ioService;
BomberMan* b = new BomberMan(m_ioService);
m_ioService.run();
return 0;
}


./aTimeToKill
BomberMan ready
Bomb placed @9c27198
tick ..
tick ..
tick ..
tick ..
tick ..
tick ..
tick ..
tick ..
tick ..
tick ..
Defusing TimeBomb
Bomb defused @9c27198
Timer aborted: Operation canceled @9c27198

删除后打印最后一行,说明我的问题。

最佳答案

解决这个问题的典型方法是使用shared_ptr

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>

#include <iostream>

using namespace std;

struct TimeBomb : public boost::enable_shared_from_this<TimeBomb>
{
bool m_active;
boost::asio::deadline_timer m_runTimer;

TimeBomb(boost::asio::io_service& ioService)
: m_active(true)
, m_runTimer(ioService)
{
cout << "Bomb placed @"<< hex << this << endl;
m_runTimer.expires_from_now(boost::posix_time::millisec(1000));
}

void start()
{
m_runTimer.async_wait(boost::bind(&TimeBomb::executeStepFunction, shared_from_this(), _1));
}

void stop()
{
m_runTimer.cancel();
}

~TimeBomb()
{
m_active = false;
m_runTimer.cancel();
cout << "Bomb defused @"<< hex << this << endl;
}

void executeStepFunction(const boost::system::error_code& error)
{
// Canceled timer
if (error == boost::asio::error::operation_aborted)
{
std::cout << "Timer aborted: " << error.message() << " @" << std::hex << this << std::endl;
return;
}
if (m_active)
{
// Schedule next step
cout << "tick .." <<endl;
m_runTimer.expires_from_now(
boost::posix_time::millisec(1000));
m_runTimer.async_wait(boost::bind(&TimeBomb::executeStepFunction, shared_from_this(), _1));
}
}
};

struct BomberMan
{
boost::asio::deadline_timer m_selfDestructTimer;
boost::shared_ptr<TimeBomb> myBomb;

BomberMan(boost::asio::io_service& ioService)
: m_selfDestructTimer(ioService)
{
cout << "BomberMan ready " << endl;
myBomb.reset( new TimeBomb(ioService) );
myBomb->start();
m_selfDestructTimer.expires_from_now(boost::posix_time::millisec(10500));
m_selfDestructTimer.async_wait(boost::bind(&BomberMan::defuseBomb, this, _1));
}

void defuseBomb(const boost::system::error_code& error)
{
cout << "Defusing TimeBomb" << endl;
myBomb->stop();
}
};


int main()
{
boost::asio::io_service m_ioService;
BomberMan* b = new BomberMan(m_ioService);
m_ioService.run();
return 0;
}

关于c++ - 如何防止截止时间计时器调用已删除类中的函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13070754/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com