Col*_*lin 1 macos qt multithreading sleep
我在 OS X 上的 Qt 应用程序中有一个后台线程,用于收集数据。线程应该在每次迭代之间休眠 100 毫秒,但它并不总是正常工作。当应用程序是最顶层的 OS X 应用程序时,睡眠工作正常。但如果不是,睡眠会持续任意时间,最多约 10 秒,大约运行一分钟后。
这是一个演示问题的简单 Cocoa 应用程序(注意 .mm for objc++)
AppDelegate.mm:
#import "AppDelegate.h"
#include <iostream>
#include <thread>
#include <libgen.h>
using namespace std::chrono;
#define DEFAULT_COLLECTOR_SAMPLING_FREQUENCY 10
namespace Helpers {
uint64_t time_ms() {
return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
}
}
std::thread _collectorThread;
bool _running;
@interface AppDelegate ()
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
_running = true;
uint64_t start = Helpers::time_ms();
_collectorThread =
std::thread (
[&]{
while(_running) {
uint64_t t1, t2;
t1 = Helpers::time_ms();
std::this_thread::sleep_for((std::chrono::duration<int, std::milli>)(1000 / DEFAULT_COLLECTOR_SAMPLING_FREQUENCY));
t2 = Helpers::time_ms();
std::cout << (int)((t1 - start)/1000) << " TestSleep: sleep lasted " << t2-t1 << " ms" << std::endl;
}
});
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
_running = false;
_collectorThread.join();
}
@end
Run Code Online (Sandbox Code Playgroud)
标准输出:
0 TestSleep: sleep lasted 102 ms. // Window is in background
0 TestSleep: sleep lasted 101 ms. // behind Xcode window
0 TestSleep: sleep lasted 104 ms
0 TestSleep: sleep lasted 104 ms
0 TestSleep: sleep lasted 105 ms
0 TestSleep: sleep lasted 105 ms
0 TestSleep: sleep lasted 105 ms
0 TestSleep: sleep lasted 104 ms
0 TestSleep: sleep lasted 102 ms
0 TestSleep: sleep lasted 102 ms
1 TestSleep: sleep lasted 105 ms
1 TestSleep: sleep lasted 105 ms
1 TestSleep: sleep lasted 104 ms
1 TestSleep: sleep lasted 101 ms
1 TestSleep: sleep lasted 101 ms
1 TestSleep: sleep lasted 100 ms
...
...
52 TestSleep: sleep lasted 102 ms
52 TestSleep: sleep lasted 101 ms
52 TestSleep: sleep lasted 104 ms
52 TestSleep: sleep lasted 105 ms
52 TestSleep: sleep lasted 104 ms
52 TestSleep: sleep lasted 100 ms
52 TestSleep: sleep lasted 322 ms. // after ~1 minute,
53 TestSleep: sleep lasted 100 ms. // sleep gets way off
53 TestSleep: sleep lasted 499 ms
53 TestSleep: sleep lasted 1093 ms
54 TestSleep: sleep lasted 1086 ms
56 TestSleep: sleep lasted 1061 ms
57 TestSleep: sleep lasted 1090 ms
58 TestSleep: sleep lasted 1100 ms
59 TestSleep: sleep lasted 1099 ms
60 TestSleep: sleep lasted 1096 ms
61 TestSleep: sleep lasted 390 ms
61 TestSleep: sleep lasted 100 ms
61 TestSleep: sleep lasted 102 ms // click on app window
62 TestSleep: sleep lasted 102 ms // to bring it to foreground
62 TestSleep: sleep lasted 105 ms
Run Code Online (Sandbox Code Playgroud)
另一方面,以下完整程序不会减慢:
#include <iostream>
#include <thread>
#include <libgen.h>
using namespace std::chrono;
#define DEFAULT_COLLECTOR_SAMPLING_FREQUENCY 10
namespace Helpers {
uint64_t time_ms() {
return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
}
}
int main(int argc, char *argv[])
{
bool _running = true;
uint64_t start = Helpers::time_ms();
std::thread collectorThread = std::thread (
[&]{
while(_running) {
uint64_t t1, t2;
t1 = Helpers::time_ms();
std::this_thread::sleep_for((std::chrono::duration<int, std::milli>)(1000 / DEFAULT_COLLECTOR_SAMPLING_FREQUENCY));
t2 = Helpers::time_ms();
std::cout << (int)((t1 - start)/1000) << " TestSleep: sleep lasted " << t2-t1 << " ms" << std::endl;
}
});
collectorThread.join();
return 0;
}
// clang++ -std=c++14 -o testc++ main.cpp
Run Code Online (Sandbox Code Playgroud)
标准输出:
0 TestSleep: sleep lasted 100 ms
0 TestSleep: sleep lasted 101 ms
0 TestSleep: sleep lasted 105 ms
0 TestSleep: sleep lasted 105 ms
0 TestSleep: sleep lasted 100 ms
0 TestSleep: sleep lasted 100 ms
0 TestSleep: sleep lasted 101 ms
0 TestSleep: sleep lasted 104 ms
0 TestSleep: sleep lasted 101 ms
0 TestSleep: sleep lasted 104 ms
1 TestSleep: sleep lasted 102 ms
1 TestSleep: sleep lasted 101 ms
1 TestSleep: sleep lasted 101 ms
1 TestSleep: sleep lasted 101 ms
1 TestSleep: sleep lasted 100 ms
...
...
99 TestSleep: sleep lasted 101 ms
99 TestSleep: sleep lasted 105 ms
99 TestSleep: sleep lasted 104 ms
100 TestSleep: sleep lasted 104 ms
100 TestSleep: sleep lasted 101 ms
100 TestSleep: sleep lasted 104 ms
Run Code Online (Sandbox Code Playgroud)
我原来的应用程序是 QML,也表现出同样的减速行为。
TestSleep.pro:
QT += quick
CONFIG += c++11
SOURCES += \
main.cpp
RESOURCES += qml.qrc
Run Code Online (Sandbox Code Playgroud)
主.qml:
import QtQuick 2.9
import QtQuick.Controls 2.2
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Scroll")
ScrollView {
anchors.fill: parent
ListView {
width: parent.width
model: 20
delegate: ItemDelegate {
text: "Item " + (index + 1)
width: parent.width
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
主.cpp:
#define DEFAULT_COLLECTOR_SAMPLING_FREQUENCY 10
namespace Helpers {
uint64_t time_ms() {
return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
}
}
int main(int argc, char *argv[])
{
bool _running = true;
QThread *collectorThread = QThread::create(
// std::thread collectorThread = std::thread (
[&]{
while(_running) {
uint64_t t1;
t1 = Helpers::time_ms();
QThread::msleep(1000 / DEFAULT_COLLECTOR_SAMPLING_FREQUENCY);
// std::this_thread::sleep_for((std::chrono::duration<int, std::milli>)(1000 / DEFAULT_COLLECTOR_SAMPLING_FREQUENCY));
t1 = Helpers::time_ms() - t1;
std::cout << "TestUSleep: sleep lasted " << t1 << " ms" << std::endl;
}
});
collectorThread->start();
collectorThread->setPriority(QThread::TimeCriticalPriority);
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
int returnValue = app.exec();
// collectorThread.join();
collectorThread->quit();
collectorThread->wait();
collectorThread->deleteLater();
return returnValue;
}
Run Code Online (Sandbox Code Playgroud)
标准输出:
0 TestSleep: sleep lasted 101 ms
0 TestSleep: sleep lasted 100 ms
0 TestSleep: sleep lasted 101 ms
0 TestSleep: sleep lasted 100 ms
0 TestSleep: sleep lasted 102 ms
0 TestSleep: sleep lasted 100 ms
0 TestSleep: sleep lasted 102 ms
0 TestSleep: sleep lasted 101 ms
0 TestSleep: sleep lasted 101 ms
0 TestSleep: sleep lasted 101 ms
1 TestSleep: sleep lasted 100 ms
1 TestSleep: sleep lasted 101 ms
1 TestSleep: sleep lasted 101 ms
1 TestSleep: sleep lasted 101 ms
...
...
63 TestSleep: sleep lasted 100 ms
63 TestSleep: sleep lasted 101 ms
63 TestSleep: sleep lasted 102 ms
63 TestSleep: sleep lasted 101 ms
63 TestSleep: sleep lasted 101 ms
63 TestSleep: sleep lasted 7069 ms # slows down
70 TestSleep: sleep lasted 235 ms
70 TestSleep: sleep lasted 10100 ms
80 TestSleep: sleep lasted 7350 ms
88 TestSleep: sleep lasted 10100 ms
98 TestSleep: sleep lasted 3566 ms
101 TestSleep: sleep lasted 100 ms
102 TestSleep: sleep lasted 3242 ms
105 TestSleep: sleep lasted 2373 ms
107 TestSleep: sleep lasted 100 ms # click on main window
107 TestSleep: sleep lasted 101 ms # to put app on top
107 TestSleep: sleep lasted 101 ms # and back to normal
107 TestSleep: sleep lasted 101 ms # behavior
108 TestSleep: sleep lasted 101 ms
108 TestSleep: sleep lasted 102 ms
...
Run Code Online (Sandbox Code Playgroud)
当使用 std::thread 而不是 QThread (在代码中注释掉)时,行为是相同的。
你看到的是苹果的省电App Nap功能的效果。
您可以通过运行 Apple 的 Activity Manager 程序并查看“App Nap”列(您可能需要右键单击进程表的标题栏以首先使该列可见)来验证是否是 App Nap 是罪魁祸首。如果您的程序正在应用程序中,您将在该列中看到表中程序行的“是”。
如果您想以编程方式为您的程序禁用 app-nap,您可以将此 Objective-C++ 文件放入您的程序并调用 main() 顶部的 disable_app_nap() 函数:
#import <Foundation/Foundation.h>
#import <Foundation/NSProcessInfo.h>
void disable_app_nap(void)
{
if ([[NSProcessInfo processInfo] respondsToSelector:@selector(beginActivityWithOptions:reason:)])
{
[[NSProcessInfo processInfo] beginActivityWithOptions:0x00FFFFFF reason:@"Not sleepy and don't want to nap"];
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
397 次 |
| 最近记录: |