【问题标题】:QApplication is lazy (or making other threads lazy in the app)QApplication 是惰性的(或使应用程序中的其他线程变得惰性)
【发布时间】:2015-08-21 13:58:17
【问题描述】:

这是我在这里的第一篇文章,我希望找到解决我的问题的方法。我已经开始使用 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。

这解决了我的问题。

【问题讨论】:

  • 你的 std::thread 不能被系统重新调度,你觉得呢?这是一个问题。系统不知道您相当空闲的线程打算做什么,并且可能会给或不给它一段时间。那些建议您使用 QTimer 或其他类型的计时器的人当然是对的。如果您无法实现正常的解决方案,那么问题出在您的处理方式上。
  • 1.您使用的是哪个版本的 Qt? 2. 你的硬件是什么? 3、调用QThread::usleep(QThread的一个静态方法)有什么不同吗?
  • Alexander,如果你仔细阅读,我提到上面的代码在没有 qapplication 的情况下也能正常工作。另一件事是相同的代码在 ubuntu 中运行良好。所以这肯定和mac有关。
  • Timday,我使用的是 Qt 5.4 版。我的硬件是英特尔 i5。使用 QThread::usleep 也有同样的问题。

标签: c++ multithreading macos qt qapplication


【解决方案1】:

听起来很多类似于here 描述的问题,在这种情况下,solution 禁用 Apple 的省电“定时器合并”(显然是在 10.9 中引入)可能会对您有所帮助。 p>

(如果 QApplication 特别导致了问题,可能是因为它的 C++ 小部件支持正在调用一些确实需要更新到 Mac 的 Grand Central Dispatch 的旧 Mac API。如果您使用的是最近的 Qt - 尝试过 5.5 测试版? - 看到这一点,可能值得提交bug report。但实际上,特别是对于“新应用程序”,您应该考虑放弃 QGuiApplication 的 C++ 小部件和 QtQuick UI 的精彩世界。

【讨论】:

  • Timday,谢谢您的回复。我现在没有mac。我明天将尝试解决方案并在此处发布结果。另一件事是该解决方案需要root权限。此应用程序将由客户端使用,它不需要 root 访问权限。您知道任何其他不需要 root 访问权限的解决方法吗?另外,我认为问题出在 QApplication 中,因为正如我所说,如果我使用 QCoreApplication 代替它可以正常工作。我向 Qt 支持发送了电子邮件,与他们讨论这个问题。
  • 确实我在您提供的链接中遇到了问题。我还阅读了paper。现在我更好地理解了为什么我遇到了 QApplication 的问题,而不是 QCoreApplication 的问题。在示例代码中,我使用 QApplication 但我没有任何东西要显示,所以这就是为什么 App Nap 认为我不需要应用程序并且有时会使应用程序睡眠时间更长。对于 QCoreApplication,我猜它认为该应用程序是后台应用程序并让我们完成它的工作。不过我不确定。
  • 你比我现在更了解这个问题。我主要觉得这类问题很有趣,因为虽然 Qt 旨在为不同平台提供一个很好的通用 API……但这些平台的现实和怪癖有一种打破门面的习惯。
猜你喜欢
  • 2017-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多