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