QApplication是惰性的(或者使应用程序中的其他线程变为惰性的)

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

本文关键字:线程 其他 或者 QApplication 应用程序      更新时间:2023-10-16

这是我在这里的第一个帖子,我希望找到一个解决我的问题的方法。我已经开始使用Qt为Mac开发一个应用程序,我现在面临着一个巨大而令人沮丧的问题。

我的问题是QApplication事件循环在20-50秒后变得懒惰(或使应用程序中的其他线程变得懒惰)。我试着重复同样的问题,得出了下面的代码:

我是这样做的。我创建了一个c++新线程,新线程每2秒打印一次当前时间。问题是在10-30次迭代之后,一些迭代需要6-12秒,这是不应该发生的,因为我在每次迭代中只睡了2秒。我运行了下面的代码,输出如下:

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$

当我运行这个程序时,每次都发生同样的问题。我不确定如果其他人试图这样做,是否会发生同样的问题。但是在我的机器里却发生了。

下面没有QApplication的代码工作得很好。因此,请不要责怪c++线程或ussleep或内核的线程管理等。另一个奇怪的事情是,当我使用QCoreApplication而不是QApplication时,它也能很好地工作。此外,我在基于ubuntu的机器上使用了相同的代码,它在QApplication上工作得很好。我想这只会发生在Mac上(我还没有尝试过windows)。

请不要建议使用QThread, QTimer或QTimer::singleShot。我刚开始用的时候也遇到了同样的问题。我正在使用QTimer和QThread的信号,问题是信号没有及时发出,或者信号及时发出,但插槽没有及时调用。延迟是相似的(6 - 12秒)。实际上,这就是为什么我使用c++线程,因为我认为使用c++线程可以解决问题,但它没有。

任何帮助都是感激的。

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

代码: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
编辑:

多亏了今天,我解决了我的问题。我在timday提供的链接中遇到了问题。是应用程序的小睡让我的应用程序进入了睡眠状态,所以我才会有定时器和睡眠问题。它只发生在QApplication而不是QCoreApplication的原因是,当我使用QApplication时,mac认为我有ui。所以当我的应用程序不活动时,mac可以让我的应用程序进入睡眠状态。

解决方法是以编程方式禁用app nap。我在C/c++中找不到api,但在这个链接中有objective C中的api。所以我在c++中调用了objective - c

有c头文件appap .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

然后是appap .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];
}

将这些行添加到您的.pro文件中:

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

当你不想让你的app在你的操作开始前调用disableAppNap,在你的操作结束后调用enableAppNap。

我的问题解决了

听起来很像这里描述的问题,在这种情况下,禁用Apple省电的"计时器合并"(显然在10.9中引入)的解决方案可能会对您有所帮助。

(如果QApplication特别导致了这个问题,那可能是因为它的c++小部件支持调用了一些旧的Mac API,这些API确实需要更新到Mac的Grand Central Dispatch。如果你使用的是最近的Qt——试过5.5测试版吗?看到这一点,提交一个bug报告可能是非常值得的。但实际上,特别是对于一个"新应用程序",您应该考虑放弃c++小部件,转而使用QGuiApplication和QtQuick UI的奇妙世界。