【问题标题】:How to delete boost io_service如何删除 boost io_service
【发布时间】:2016-10-21 18:15:43
【问题描述】:

我的简化问题
我读了this thread 并试图删除 io_service 对象。我这样做

m_IO.stop();
m_IO.~io_service();

m_IO 是boost::asio::io_service 的对象。我发现我的帖子被m_IO.~io_service(); 阻止了如何删除io_service

我的完整问题
我正在使用 boost io_service 和截止日期计时器制作每日计时器。问题是当我想删除我的每日计时器时,我的线程在尝试删除 boost io_service 时会消失。

main.cpp

int main()
{
    myDailyTimer* pTimer = new myDailyTimer;
    // do something
    delete pTimer;
    return 0;
}

我在myDailyTimer.cpp::int i = 0;myDailyTimer.cpp::int j = 0;main::return 0;设置断点我的主线程可以到达int i = 0;,我的定时器线程无法到达int j = 0;,我的主线程无法到达return 0;
我发现我的主线程在尝试删除 boost::asio::io_service 对象时会消失。如何解决这个问题呢?我是否以错误的方式使用boost::asio::io_service

myDailyTimer.h

class myDailyTimerInterface
{
public:
    myDailyTimerInterface(){}
    ~myDailyTimerInterface(){}

    virtual void TimerCallback(int nTimerID) = 0;
};
class myDailyTimer :
    public myThread
{
public:
    boost::asio::io_service m_IO;
    boost::asio::deadline_timer * m_pTimer;
    tm m_tmSpecificTime;
    std::string m_strSpecificTime;
    int m_nTimerID;
    myDailyTimerInterface* m_pParent;
public:
    myDailyTimer();
    ~myDailyTimer();

    void SetTime(tm strIN, int nID); // msec
    void TimerCallback();

    //Override
    void ThreadMain();
protected:
    std::string MakeStringSpecificTime();
    void AddOneDay();
};


myDailyTimer.cpp

myDailyTimer::myDailyTimer()
{
    m_pTimer = 0;
    m_strSpecificTime = "";
}

myDailyTimer::~myDailyTimer()
{
    EndThread();
    if (m_pTimer != 0)
    {
        m_pTimer->cancel();
        delete m_pTimer;
    }
    m_IO.stop();
    m_IO.~io_service();
    int i = 0;
    i++;
}

void myDailyTimer::SetTime(tm tmIN, int nID) // msec
{
    if (m_pTimer != 0)
    {
        m_pTimer->cancel();
        delete m_pTimer;
    }
    m_tmSpecificTime = tmIN;
    m_strSpecificTime = MakeStringSpecificTime();
    m_nTimerID = nID;
    m_pTimer = new boost::asio::deadline_timer(m_IO, boost::posix_time::time_from_string(m_strSpecificTime));
    m_pTimer->async_wait(boost::bind(&myDailyTimer::TimerCallback, this));

    myThread::Start();
}

std::string myDailyTimer::MakeStringSpecificTime()
{
    time_t localTime;
    localTime = mktime(&m_tmSpecificTime); // time is GMT local
    struct tm * ptm = gmtime(&localTime); // convert time to GMT +0
    char veccNextTime[64];
    memset(veccNextTime, 0, sizeof(veccNextTime));
    sprintf(veccNextTime, "%d-%02d-%02d %02d:%02d:%02d.000",
        ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday,
        ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
    std::string strTemp(veccNextTime);
    return strTemp;
}

void myDailyTimer::AddOneDay()
{
    m_tmSpecificTime.tm_mday += 1;
    mktime(&m_tmSpecificTime); /* normalize result */
}

void myDailyTimer::TimerCallback()
{
    if (m_pParent != 0)
        m_pParent->TimerCallback(m_nTimerID);
    //m_timer->expires_from_now(boost::posix_time::milliseconds(m_nTimerDuration));
    AddOneDay();
    m_strSpecificTime = MakeStringSpecificTime();
    m_pTimer->expires_at(boost::posix_time::time_from_string(m_strSpecificTime));
    m_pTimer->async_wait(boost::bind(&myDailyTimer::TimerCallback, this));
}

//Override
void myDailyTimer::ThreadMain()
{
    while (!IsEndThread())
        m_IO.run();
    int j = 0;
    j++;
}


【问题讨论】:

  • m_IO.~io_service(); -- 如果我曾经见过,那就是代码味道,尤其是在这种情况下。您提到的问题特别提到用户无法控制相关代码,因此他们不得不诉诸这种恶作剧(无论如何您都没有正确实现,因为您没有重新创建对象)。如果您需要更好地控制其生命周期,该问题还包含一条带有明智建议动态分配io_service 的评论。但是,这与此处无关,因为问题出在其余代码上,而不是删除 io_service
  • 谢谢你的回复,如果我想在deadline_timer的帮助下实现一个每日定时器,我该怎么办?
  • 我正在研究一个答案,但请给我一些时间来整理。
  • 不要直接使用asio::io_service,而是使用boost::optional<asio::io_service>,在构造函数中初始化它,然后调用m_IO.~io_service而不是调用m_IO.reset()。我在任何地方都没有看到你的 EndThread 函数,所以我只是要注意,你必须确保线程是 joined 并且在销毁 @ 之前销毁每个 asio IO 对象(例如 m_pTimer) 987654349@.

标签: c++ boost


【解决方案1】:

正如 Dan Mašek 所提到的,在这里显式调用析构函数并不是一个好的模式。停止io_service 的标准方法是停止所有待处理的“工作”,然后等待io_service::run 函数返回。此外,为了防止io_service::run 函数过早返回,最好创建一个io_service::work 对象的实例。

希望您能够根据您的用例修改此示例:

namespace asio = boost::asio;

class MyTimer {
    using Clock = std::chrono::steady_clock;

  public:
    MyTimer(Clock::duration duration) 
      : _work(_ios)
      , _timer(_ios)
      , _thread([this] { _ios.run(); })
    {
      _ios.post([this, duration] { start(duration); });
    }

    ~MyTimer() {
      _ios.post([this] { stop(); });
      _thread.join();
    }

  private:
    void start(Clock::duration duration) {
      _timer.expires_from_now(duration);
      _timer.async_wait([this](boost::system::error_code) {
          // NOTE: Be careful here as this is run from inside
          //       the thread.
          if (!_work) {
            // Already stopped.
            std::cout << "Stopped" << std::endl;
            return;
          }
          std::cout << "Timer fired" << std::endl;
        });
    }

    void stop() {
      _work.reset();
      _timer.cancel();
    }

  private:
    asio::io_service _ios;
    boost::optional<asio::io_service::work> _work;
    asio::steady_timer _timer;
    std::thread _thread;
};

int main() {
  auto* my_timer = new MyTimer(std::chrono::seconds(1));
  delete my_timer;
  return 0;
}

【讨论】:

  • 非常感谢,我试过后标记为答案。
猜你喜欢
  • 2015-04-22
  • 1970-01-01
  • 1970-01-01
  • 2017-09-17
  • 2013-08-07
  • 2011-06-16
  • 2011-09-17
  • 2021-02-22
  • 1970-01-01
相关资源
最近更新 更多