c-QApplication是惰性的(或使其他线程在应用程序中是惰性的)

这是我在这里的第一篇文章,我希望找到解决我问题的方法.我已经开始使用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线程或usleep或内核来进行线程管理等.另一个奇怪的是,当我使用QCoreApplication而不是QApplication时,它也可以正常工作.此外,我在基于ubuntu的计算机上使用了相同的代码,并且可以与QApplication一起正常工作.我猜这只会在Mac中发生(尽管我没有尝试过Windows).

请不要建议使用QThread,QTimer或QTimer :: singleShot.我刚开始使用它们时遇到了同样的问题.我在QTimer和QThread中使用了信号,问题是信号没有及时发出或信号没有及时发出,但是没有及时调用插槽.等待时间相似(6-12秒).实际上,这就是我使用c线程的原因,因为我认为使用c线程可以解决问题,但事实并非如此.

任何帮助表示赞赏.

作业系统:MAC OSX 10.9.5.

uname -a输出:

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,我解决了我的问题. timday提供的链接中有问题.正是应用程序午睡使我的应用程序进入睡眠状态,这就是为什么我遇到计时器和睡眠问题的原因.它仅发生在QApplication而不发生在QCoreApplication上的原因是,当我使用QApplication时,mac认为我正在使用ui.因此,当我的应用程序不活动时,mac可以使我的应用程序进入睡眠状态.

解决方法是以编程方式禁用应用程序午睡.我在C/C++中找不到api,但是在link中,目标c中有api.所以我只是从c调用了目标c.

具有C头文件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

然后有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];
}

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

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

然后,当您不希望应用程序午睡使应用程序进入睡眠状态时,请在操作开始之前调用disableAppNap,并在操作结束之后调用enableAppNap.

这解决了我的问题.

解决方法:

听起来很像here中描述的问题,在这种情况下,禁用Apple的节电“计时器合并”(显然是在10.9中引入)的solution可能会对您有所帮助.

(如果QApplication专门导致了该问题,可能是因为其C小部件支持正在调用某些旧的Mac API,实际上确实需要将其更新为Mac的Grand Central Dispatch.如果您使用的是最近的Qt,请尝试5.5 beta吗?-并看到为此,可能值得提交bug report.但是,实际上,特别是对于“新应用程序”,您应该考虑放弃QGuiApplication和QtQuick UI美好世界的C小部件.

上一篇:Qt事件分发机制源码分析之QApplication对象构建过程


下一篇:第25天 | 28天学会PyQt5,高级控件之QTableWidget