Qt应用中的升压定时器

时间:2014-03-26 22:24:26

标签: c++ qt boost

我试图创建使用boost中的计时器的qt应用程序, 我有以下代码的问题 在osx上编译,qt 5.2,提升1.55

这是我的代码:

CCTimer::CCTimer(int interval)
    : m_pingTimer(m_ioServiceTimer, boost::posix_time::seconds(interval)), m_interval(interval)
{
    m_isRunning = false;
}

CCTimer::~CCTimer()
{
    Stop();
}

void CCTimer::Start()
{
    if(!m_isRunning)
    {
        m_isRunning = true;
        Reset(m_interval);
        m_timerThread = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&boost::asio::io_service::run, &m_ioServiceTimer)));
    }
}

void CCTimer::Reset(int durationTime)
{
    m_beforeTime = boost::posix_time::microsec_clock::universal_time();
    m_pingTimer.expires_from_now(boost::posix_time::seconds(durationTime));
    m_pingTimer.async_wait(boost::bind(&CCTimer::Wait, this, _1));
}

void CCTimer::Wait(const boost::system::error_code& errorCode)
{
    boost::posix_time::time_duration duration = boost::posix_time::microsec_clock::universal_time() - m_beforeTime;
    std::cout << boost::posix_time::microsec_clock::universal_time() << std::endl;
    if(duration.seconds() > m_interval) {
        std::cout << "Error time " << std::endl;
    }
    Reset(m_interval);
}

void CCTimer::Stop()
{
    if(m_isRunning)
    {
        m_isRunning = false;
        m_pingTimer.cancel();
        m_ioServiceTimer.stop();
        m_timerThread->join();
        m_ioServiceTimer.reset();
    }
}

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    CCTimer timer(1);
    timer.Start();

    return app.exec();
}

在qt应用程序中创建计时器后,控制台显示:

2014-Mar-26 22:04:30.549722
2014-Mar-26 22:04:31.550977
2014-Mar-26 22:04:32.552229
2014-Mar-26 22:04:33.553467
2014-Mar-26 22:04:34.554734
2014-Mar-26 22:04:43.684300
Error time 
2014-Mar-26 22:04:54.694440
Error time 
2014-Mar-26 22:05:05.694371
Error time 
2014-Mar-26 22:05:11.669329
Error time 

什么可能是错的?

1 个答案:

答案 0 :(得分:1)

我没有发现任何明显的东西。当然,你从不提及是否/何时/在哪里上课Stop()Start()

我使实施稍微简单并修复了一些潜在的比赛:

  • 没有无用的时间线程的共享指针
  • 使CCTimer不可复制
  • 不再是m_isRunning kludge;相反,故意取消计时器并检测取消,以便您可以结束线程。如果该帖子是joinable(),那么它正在运行
  • 修复了一个竞争条件,你从调用Stop()的线程中取消定时器,而io_service线程异步等待定时器,也将取消发布到io_service线程:< / p>

    void Stop()
    {
        if(m_thread.joinable())
        {
            m_service.post(boost::bind(&deadline_timer::cancel, &m_timer));
            m_thread.join();
            m_service.stop();
            m_service.reset();
        }
    }
    
  • 修复了一种化妆品,如果你使用不同的时间戳进行打印而不是计算经过的时间,那会导致混淆

<强>更新

所以我下载了Qt5并引导我的编译器使用它。 /巨大的成功/。事实上,我有同样的行为(但有时甚至更糟)。奇怪的是它终端上的阻塞比最终输出显示的要多。这让我怀疑它可能是Qt为了它自己的目的而截取/重新打开stdin / stdout流,并在此过程中添加了一些阻塞/缓冲行为。

我通过将计时器跟踪写入单独的文件来检查这一点,实际上这消除了症状(当运行超过一小时时)。所以这可能是你问题的原因。 只是不要从你的计时器线程写入stdout,你的虚假阻止问题应该消失

以下是我用来测试此代码的代码,其中包含以上建议:

#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <QtGui/QGuiApplication>
#include <QtCore/QCoreApplication>
#include <fstream>

using namespace boost::asio;
namespace pt = boost::posix_time;

class CCTimer : boost::noncopyable
{
    io_service     m_service;
    deadline_timer m_timer;
    pt::ptime      m_starttime;
    int            m_interval_seconds;
    boost::thread  m_thread;
    std::ofstream  ofs;

  public:
    CCTimer(int interval)
        : m_service(),
          m_timer(m_service), 
          m_interval_seconds(interval)
    {
        assert(m_interval_seconds>0);
    }

    ~CCTimer()
    {
        Stop();
    }

    void Start()
    {
        if(!m_thread.joinable())
        {
            ofs.open("output.log");
            Reset(m_interval_seconds);
            m_thread = boost::thread(boost::bind(&io_service::run, &m_service));
        }
    }

    void Stop()
    {
        if(m_thread.joinable())
        {
            m_service.post(boost::bind(&deadline_timer::cancel, &m_timer));
            m_thread.join();
            ofs.close();
            m_service.stop();
            m_service.reset();
        }
    }

  private:
    static pt::ptime now() { return pt::microsec_clock::universal_time(); }

    void Reset(int durationTime)
    {
        m_timer.expires_from_now(pt::seconds(durationTime));
        m_starttime = now();
        m_timer.async_wait(boost::bind(&CCTimer::Elapsed, this, placeholders::error));
    }

    void Elapsed(const boost::system::error_code& errorCode)
    {
        pt::ptime const event           = now();
        pt::time_duration const elapsed = event - m_starttime;

        if (errorCode != error::operation_aborted && ofs.is_open() && ofs.good())
        {
            ofs << event << " (" << elapsed.total_milliseconds() << "ms) ";

            if(elapsed.seconds() > m_interval_seconds) {
                ofs << " Overdue!" << std::endl;
            } else {
                ofs << "" << std::endl;
            }

            Reset(m_interval_seconds);
        } else
        {
            ofs << "Stopped (" << elapsed.total_milliseconds() << "ms)" << std::endl;
        }
    }

};

int main(int argc, char** argv)
{
    QGuiApplication app(argc, argv);

    CCTimer timer(1);
    timer.Start();

    return app.exec();
}

旧建议:

我必须假设您在禁止CCTimer线程的其余代码中执行某些操作

  • 你是在调试器,分析器,什么?下运行的?
  • 你是在一个(不堪重负的)虚拟化器下运行的吗?
  • 你在同一个io_service / thread?
  • 上做得更多吗?
  • 可以阻止IO吗?特别是您将时间戳记录到实际控制台或文件/管道?输出管道是否会阻塞计时器线程?