2

我一直在研究一个简单的对话框小部件,它应该以 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 使用率,除非gettimeofdayQTime或者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;
};
4

2 回答 2

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 文档指出:

“准确性和计时器分辨率计时器永远不会早于指定的超时值超时,并且它们不能保证在指定的确切值处超时。在许多情况下,它们可能会延迟一段时间,具体取决于时间的准确性系统计时器。计时器的准确性取决于底层操作系统和硬件。大多数平台支持 1 毫秒的分辨率,尽管在许多实际情况下计时器的准确性不会等于此分辨率。如果 Qt 无法提供请求的计时器点击次数,它会默默地丢弃一些。”

但是如果线程被阻塞/忙碌,我发现这在 Windows 7 x64 上不是真的。

于 2013-09-04T13:01:50.173 回答
0
deadman->start(10); // 10 ms;

(注意:问题之前写的答案被固定为有 100 毫秒的间隔)

这里有 10ms 的间隔,即 100Hz,而不是 10Hz。在您的问题中,您说“我正在使用的系统运行了好几天”,所以听起来您有某种嵌入式系统?也许它无法跟上 100Hz 定时器。

请注意,每秒更新标签 100 次会导致QWidget::update()经常被调用,并且小部件将经常从事件循环中绘制,即使您不调用repaint()(无论如何都不应该这样做)。

于 2013-09-04T12:48:35.477 回答