Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
301 views
in Technique[技术] by (71.8m points)

c++ - QApplication is lazy (or making other threads lazy in the app)

This is my first post here and I hope to find a solution to my problem. I have started developing an app for Mac using Qt. I am facing a huge and frustrating problem right now.

My problem is QApplication event loop becomes lazy (or makes other threads lazy in the app) after 20-50 seconds. I tried to replicate the same problem and came up with the code below.

So here is what I do. I create a c++ new thread and the new thread prints the current time in every 2 seconds. The problem is after 10-30 iterations, some iterations take 6-12 seconds which shouldn't happen because I just sleep 2 seconds in every iteration. I ran the code below and the output is like this:

sumits-air:UbiqMac_qt Jay$ ./run.sh
"05.06.2015 16:43:30"
"05.06.2015 16:43:32"
"05.06.2015 16:43:34"
"05.06.2015 16:43:36"
"05.06.2015 16:43:38"
"05.06.2015 16:43:40"
"05.06.2015 16:43:42"
"05.06.2015 16:43:44"
"05.06.2015 16:43:46"
"05.06.2015 16:43:48"
"05.06.2015 16:43:50"
"05.06.2015 16:43:52"
"05.06.2015 16:43:54"
"05.06.2015 16:43:56"
"05.06.2015 16:43:58"
"05.06.2015 16:44:00"
"05.06.2015 16:44:02"
"05.06.2015 16:44:04"
"05.06.2015 16:44:06" (- 06 here)
"05.06.2015 16:44:18" (- 18 here. 12 seconds difference)
"05.06.2015 16:44:24" (- 24 here. 6 seconds difference)
"05.06.2015 16:44:26"
"05.06.2015 16:44:28"
"05.06.2015 16:44:30"
^C
sumits-air:UbiqMac_qt Jay$

When I run this program, every single time the same problem happens. I am not sure if the same problem will happen if someone else tries to do it. But it happens in my machine.

The code below without QApplication works fine. So please do not blame c++ thread or usleep or the kernel for thread management or so. The other strange thing is that when I use QCoreApplication instead of QApplication it works fine as well. In addition, I use the same code in ubuntu based machine and it works fine with QApplication. I guess this only happens in Mac (I haven't tried windows though).

Please do not suggest using QThread, QTimer or QTimer::singleShot. I was using them at first and having the same problem. I was using signals with QTimer and QThread and the problem was that signals were not emitted in time or signals emitted in time but the slots were not called in time. The latency was similar (6 - 12 seconds). Actually, that is why I am using c++ thread because I thought using c++ thread may solve the problem but it didn't.

Any help is appreciated.

OS: MAC OSX 10.9.5.

uname -a output:

Darwin 13.4.0 Darwin Kernel Version 13.4.0:
root:xnu-2422.115.4~1/RELEASE_X86_64 x86_64

The Code: main.cpp:

#include <QApplication>
#include <QDebug>
#include <QDateTime>

#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <thread>

void test() {
     while(true) {
          qDebug() << QDateTime::currentDateTime().toString("dd.MM.yyyy hh:mm:ss");
          usleep(2000000);
     }
}

int main(int argc, char *argv[]) {
     QApplication a(argc, argv);
     std::thread *heartbeatThread = new std::thread(&test);
     a.exec();
     heartbeatThread->join();
     return 0;
}

test.pro:

QMAKE_CXXFLAGS += -std=c++11
QMAKE_CXXFLAGS += -stdlib=libc++
LIBS += -stdlib=libc++
QT += core gui widgets
TARGET = test
TEMPLATE = app
SOURCES += main.cpp

EDIT:

I solved my problem thanks to timday. I was having the problem in the link that timday provided. It was the app nap that was making my app sleep so that is why I was having timer and sleep problems. The reason it only happens to QApplication but not to QCoreApplication is that mac thinks that I am having ui when I use QApplication. So when my app is not active then mac can put my app to sleep.

The workaround was to disable app nap programmatically. I couldn't find api in C/C++ for it but there is api in objective c in this link. So I just called objective c from c++.

Have c header file appnap.h:

#ifndef __APP_NAP__
#define __APP_NAP__

#if !defined(__cplusplus)
#define C_API extern
#else
#define C_API extern "C"
#endif

C_API void disableAppNap();
C_API void enableAppNap();

#endif

Then have appnap.m:

#include "appnap.h"
#include <Foundation/Foundation.h>

static id activity;

void disableAppNap() {
    activity = [[NSProcessInfo processInfo] beginActivityWithOptions:NSActivityLatencyCritical | NSActivityUserInitiated 
                                                              reason:@"Disable App Nap"];
}

void enableAppNap() {
    [[NSProcessInfo processInfo] endActivity:activity];
}

Add these lines to your .pro file:

HEADERS += appnap.h
OBJECTIVE_SOURCES += appnap.m
LIBS += -framework Foundation

Then when you don't want app nap to make your app sleep call disableAppNap before your operation begins and call enableAppNap after your operation ends.

This solved my problem.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Sounds a lot like the problem described here, in which case the solution of disabling Apple's power-saving "timer coalescing" (apparently introduced in 10.9) may help you.

(If QApplication specifically causes the problem, it's possibly because its C++ widget support is calling some old Mac API which really needs to be updated to Mac's Grand Central Dispatch. If you're on a recent Qt - tried the 5.5 beta? - and seeing this, it might be well worth filing a bug report. But really, especially for a "new application" you should consider ditching the C++ widgets for QGuiApplication and the wonderful world of QtQuick UI).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...