c++ - gettimeofday、QTime 或 QLabel->setText 中 CPU 利用率为 100%

标签 c++ linux qt

我一直在开发一个简单的对话框小部件,它应该以 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 使用率,除非 gettimeofdayQTimesetText 正在做我正在做的事情不期待。

这里的专家是否注意到这些函数有任何异常行为?

我正在使用 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)

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;
};

最佳答案

如果您的线程繁忙,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 上情况并非如此。

关于c++ - gettimeofday、QTime 或 QLabel->setText 中 CPU 利用率为 100%,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18613736/

相关文章:

c++ - opencv相机标定(Assertion failed故障)

PHP GD - 不同的文本偏移 Mac 与 Linux

c++ - 改进dll丢失错误信息

qt - 如何标记要隐藏在 QAbstractItemModel 派生模型中的行

c++ - libpthread.so 在 `dlclose()` 之后继续使用 TLS 空间和 DL 命名空间

c++ - 带有 const 修饰符的错误 - 返回类型似乎没问题

c++ - 有没有办法将 vector 成对放在方括号中

linux - 使用 libpcap 加入/离开多播组

linux - 在 linux shell 上显示日志文件的特定部分

c++ - eclipse CDT/Qt : have a Qt Gui project depend on another C++ project in the workspace