我一直在研究一个简单的对话框小部件,它应该以10 Hz的速率显示GMT时间。由于我正在进行的系统运行数天和数天,它应该是稳定的。
在一些夜间运行中,我注意到我的“BAR”程序在执行几个小时后以100%运行。我为什么会发生这种情况感到沮丧,但我已经能够将其缩小到三个功能:
我正在使用一个名为ace_time
的简单函数来获取时间:
inline double ace_time(void)
{
struct timeval tv;
struct timezone tz;
gettimeofday(&tv, &tz);
return (double) tv.tv_sec + 1e-6 * (double) tv.tv_usec;
}
然后我从这个函数的返回中获得毫秒,秒,分钟等。然后我使用QTime
格式化它:
QTime time(hours, minutes, seconds, milliseconds);
QString timeStr = time.toString("hh:mm:ss.zzz");
然后在我的标签中设置文字:
clock->setText(timeStr);
我很困惑为什么我会获得100%的cpu使用率,除非gettimeofday
,QTime
或setText
正在做我不期望的事情。
这里的专家是否注意到这些功能中的任何一个都表现得很奇怪?
我正在使用Qt 4.8,如果这有帮助的话。
期待获得一些解决这个问题的想法。谢谢!
添加更多代码:
我想要两个酒吧。顶部和底部栏。所以我写了一个BarBase
类和一个TopBar
类。我还需要编写一个自定义QLayout
来帮助我进行布局。我非常怀疑布局管理器是否会导致这种情况,因为只有在调整条形图并且需要重新计算几何图形时才会调用它。
class BarBase : public QWidget
{
public:
BarBase()
{
setFixedHeight(barHeight);
setContentsMargins(5, 0, 5, 0);
QPalette palette;
QColor color(50, 252, 50);
palette.setColor(QPalette::Background, color);
setAutoFillBackground(true);
setPalette(palette);
}
virtual ~BarBase();
protected:
QLabel *createWestLabel(const QString &);
QLabel *createCenterLabel(const QString &);
QLabel *createEastLabel(const QString &);
private:
QLabel *createLabel(const QString &, Qt::Alignment)
{
QLabel *label = new QLabel(str);
label->setAlignment(Qt::AlignVCenter | alignment);
//label->setFrameStyle(QFrame::Box | QFrame::Raised);
QFont font("Times");
font.setPixelSize(barHeight - 4);
font.setBold(true);
label->setFont(font);
return label;
}
};
这是我的TopBar
仅
class TopBar : public BarBase
{
Q_OBJECT
public:
TopBar()
{
Layout *layout = new Layout;
classification = createCenterLabel("Classification");
layout->addWidget(classification, Layout::Center);
hostname = createWestLabel("Hostname");
layout->addWidget(hostname, Layout::West);
layout->addWidget(createWestLabel(":"), Layout::West);
software = createWestLabel("Software");
layout->addWidget(software, Layout::West);
runMode = createEastLabel("SIM");
layout->addWidget(runMode, Layout::East);
layout->addWidget(createEastLabel(":"), Layout::East);
clock = createClockLabel("-dd::hh::mm::ss.z");
layout->addWidget(clock, Layout::East);
deadman = new QTimer;
connect(deadman, SIGNAL(timeout()), this, SLOT(updateLocalGMT()));
deadman->start(100); // 10 ms;
setLayout(layout);
setWindowTitle(tr("Top Bar"));
}
virtual ~TopBar();
public slots:
void updateLocalGMT()
{
double milliseconds = fmod(ace_time(), 86400.0) * 1000;
bool sign = (milliseconds >= 0.0);
if (!sign)
{
milliseconds = -milliseconds;
}
const int millisecondsToDays = 86400.0 * 1000.0;
const int millisecondsToHours = 3600.0 * 1000.0;
const int millisecondsToMinutes = 60 * 1000.0;
const int millisecondsToSeconds = 1000.0;
double days = floor(milliseconds / millisecondsToDays);
milliseconds -= days * millisecondsToDays;
double hours = floor(milliseconds / millisecondsToHours);
milliseconds -= hours * millisecondsToHours;
double minutes = floor(milliseconds / millisecondsToMinutes);
milliseconds -= minutes * millisecondsToMinutes;
double seconds = floor(milliseconds / millisecondsToSeconds);
milliseconds -= seconds * millisecondsToSeconds;
QTime time(hours, minutes, seconds, milliseconds);
/*
if (!time.isValid())
{
INFO("Invalid input to QTime [day, hour, min, sec, ms]: [%f %f %f %f %f]",
days, hours, minutes, seconds, milliseconds);
}
*/
QString timeStr = time.toString("hh:mm:ss.zzz");
timeStr = timeStr.left(timeStr.length() - 2); // to remove the last two z
timeStr.prepend((sign) ? "+" : "-");
timeStr.prepend("<code style='color:white'>");
timeStr.append("</code>");
// timeStr = timeStr.left(timeStr.length() - 2);
// qDebug() << currentTime;
clock->setText(timeStr);
}
private:
QLabel *classification;
QLabel *hostname;
QLabel *software;
QLabel *runMode;
QLabel *clock;
QLabel *createClockLabel(const QString &text)
{
QLabel *label = new QLabel(text);
label->setAlignment(Qt::AlignVCenter);
QFont font("Monospace");
font.setStyleHint(QFont::TypeWriter);
font.setFixedPitch(true); // enforces monospace
font.setPointSize(18);
font.setBold(true);
label->setFont(font);
int pixelWidth = label->fontMetrics().width(label->text());
label->setFixedWidth(pixelWidth);
return label;
}
QTimer *deadman;
};
答案 0 :(得分:2)
如果您的线程繁忙,QTimer可能会落后并排队许多通知 - 这将导致您的处理发生的次数远远超出您的预期。
要解决此问题,您应该执行以下操作:
void timer_slot()
{
if diff(now - last_time) < timer_interval
return; // Timer has come in too early so don't do anything
last_time = now;
}
如果你想重现这个只是用sleep()来阻塞你的线程,你会注意到调用定时器插槽的次数应该是在线程被阻塞时应该被调用的次数。
QTimer docs声明:
“准确度和定时器分辨率 定时器永远不会超过指定的超时值超时,并且不能保证它们以指定的确切值超时。在许多情况下,它们可能会延迟一段时间,这段时间取决于系统定时器的准确性。 定时器的准确性取决于底层操作系统和硬件。大多数平台支持1毫秒的分辨率,但在许多实际情况下,定时器的精度将不等于此分辨率。 如果Qt无法提供所需的计时器点击次数,它将默默地丢弃一些。“
但是如果线程被阻塞/忙碌,我发现在Windows 7 x64上不会出现这种情况。
答案 1 :(得分:0)
deadman->start(10); // 10 ms;
(注意:问题之前的答案被修复为100毫秒间隔)
这里有10ms的间隔,即100Hz,而不是10Hz。在你的问题中,你说“我正在运行的系统运行了几天和几天”,所以听起来你有一个某种类型的嵌入式系统?也许它无法跟上100Hz计时器。
请注意,每秒更新标签100次会导致QWidget::update()
经常被调用,并且即使您没有调用repaint()
,也会经常从事件循环中绘制窗口小部件。你不应该这样做。)