2013-09-04 1 views
2

GMT 시간을 10 Hz로 표시해야하는 간단한 대화 위젯에서 작업 해 왔습니다. 며칠이나 며칠 동안 실행중인 시스템이 안정적이어야합니다.gettimeofday, QTime 또는 QLabel-> setText에서 CPU 사용률 100 %

몇 시간 동안 실행하면 몇 시간 동안 실행 한 후에 "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

루프에서이 작업을 수행하고 있습니까? –

+0

나는 그렇게 생각하지 않는다. 나는 100ms의 타임 아웃을하는'qTimer '를 가지고 있으며,이 함수를 사용하는 슬롯에 신호를 연결했다. –

+0

이러한 함수 중 어느 것도 0.1을 사용하지는 않을 것 같습니다. 나는 당신이 게시하지 않은 코드 어딘가에 버그가 있다고 의심한다 ... –

답변

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

을) 당신은 타이머 슬롯이 많은 요구된다는 것을 알 수 있습니다 스레드가 차단되어있을 때 호출되었을 것입니다. . 것이

QTimer 워드 프로세서 상태 :

"정확성과 타이머 해상도 타이머가 밖으로 이전에 지정된 시간 제한 값보다 시간과 그들이 많은 상황에서 지정된 정확한 값에서 타임 아웃을 보장하지되지 않습니다, 그들은 시스템 타이머의 정확도에 따라 늦은 시간이 초과 될 수 있습니다. 타이머의 정확도는 기본 운영 체제 및 하드웨어에 따라 다릅니다. 대부분의 플랫폼은 1 밀리 초의 분해능을 지원하지만 타이머의 정확도는 1 밀리 초입니다. 많은 실제 상황에서이 해상도와 동일합니다. Qt가 요청한 횟수의 타이머 클릭을 전달할 수 없으면 자동으로 일부를 버립니다. "

그러나 스레드가 차단/사용 중이면 Windows 7 x64에서이 사실을 발견했습니다.

+0

타이머 이벤트가 대기 중입니까? 나는 거의 100 % 확실하지 않다. 즉, 타이머는 가능한 한 자주 불을 웁니다. "자주 불려야만합니다". 사실이라면, 버그처럼 보입니다. – hyde

+0

마지막으로 슬롯에 스레드와 대기 연결을 사용했는지 확인했습니다. – paulm

+0

아! 대기열에 놓인 신호는 대기열에 들어갑니다.따라서 한 스레드의 타이머가 요청 된 간격으로 쉽게 실행되고 신호를 계속 방출 할 수 있습니다. 결국 신호가 대기열에 들어가면 매우 가벼운 작업입니다. 그런 다음 다른 스레드는 신호를 가능한 빨리 언 큐킹했으나 스레드 간 신호에는 스로틀 메커니즘이 없습니다. 슬롯과 타이머가 같은 스레드에 있었고, 심지어 대기중인 경우 슬롯은 타이머를 차단하고 문서가 말하는 것처럼 작동했습니다. "do not do", "threading is hard") – hyde

0
deadman->start(10); // 10 ms; 

(참고 : 질문 이전에 작성된 답변은 100 밀리 간격이 고정 된) 현재 10ms의 간격이

을 10Hz가 아닌 100Hz입니다. 귀하의 질문에 "일하고있는 시스템은 며칠 동안 운영됩니다"라고 말하면서 임베디드 시스템을 가지고있는 것처럼 들리십니까? 어쩌면 100Hz 타이머를 따라 잡는 데 어려움을 겪을 수도 있습니다.

레이블을 100 초마다 업데이트하면 QWidget::update()이 자주 호출되며, repaint() (어쨌든해서는 안됨)을 호출하지 않아도 이벤트 루프에서 위젯이 자주 자주 색칠됩니다.

+0

그건 내가 디버그 코드에서 시험해보고자하는 것입니다. 100Hz로 만드는 것이 더 빨리 실패 할 수 있는지 알고 싶었습니다. 100Hz는 생산 코드가 아니며, 10Hz는 생산 코드입니다. –

+0

필자는 동의합니다. Qt 웹 사이트의 어딘가에서 타이머 스레드가 뒤떨어져 지속적으로 불을 뿜을 수 있다는 것을 알았습니다. 앱이 계속해서 다시 그려지는 것처럼 보일 것입니다. – paulm

+0

10Hz에서도 업데이트 스레드가 뒤쳐질 수 있습니까? 그걸위한 링크가 있습니까? 그것은 흥미 롭습니다. –