我试图创建使用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
什么可能是错的?
答案 0 :(得分:1)
我没有发现任何明显的东西。当然,你从不提及是否/何时/在哪里上课Stop()
和Start()
。
我使实施稍微简单并修复了一些潜在的比赛:
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?