关于在macOS上运行Qt窗口程序遇到的坑

关于在macOS上运行Qt窗口程序遇到的坑

单纯的我最近在macOS上写Qt GUI,写得还算爽,虽然C++的手动清内存还没习惯(Qt的半自动内存管理也救不了啊)。

发现问题

直到昨天试着写一个TcpServer时,才发现了不对劲,在我写TcpSocket定时发送数据(用QTimer)时,发现QTimer开始的时候是正常执行代码,过个几十秒后,程序就会停顿2、3秒(甚至10秒)

思考问题

我以为的原因一

一开始我以为是QTcpSocket::write的问题,因为QTcpSocket继承自IODevice,所以write后不一定会直接发送,而是先放入QTcpSocket的缓存空间里。所以解决方法是在write代码执行顺序后面追加代码

// 手动flush缓存
socket->flush();

然而,还是没有解决。

我以为的原因二

因为我设计TcpServer的时候为了能让TcpServer同时处理多个用户访问,所以使用多线程技术。通过重写方法:

QTcpServer::incomingConnection(qintptr handle)

来实现多线程处理socket,具体代码如下:

void TcpServer::incomingConnection(qintptr handle) {
    socket = new TcpSocket(handle);
    auto *thread = new QThread;
    socket->moveToThread(thread);
    connect(socket, &TcpSocket::disconnected, socket, &TcpSocket::onDisconnected);
    connect(socket, &TcpSocket::readyRead, socket, &TcpSocket::read);
    connect(socket, &TcpSocket::stateChanged, socket, &TcpSocket::onStatusChanged);
    connect(socket, &TcpSocket::tcpConnect, socket, &TcpSocket::onConnected);
    connect(socket, &TcpSocket::tcpDisconnect, this, &TcpServer2::onDisconnected);
    thread->start();
    
    // res是QHash,用将socket和对应的thread联系,方便最后disconnect时删除thread
    res.insert(socket, thread);
    emit socket->tcpConnect();
    emit newConnection();
}

然后聪明的我猜想:会不会是线程等级不够高,导致线程不调度时间少?

所以我特地为修改QThread::start方法:

// 最高优先级了
thread->start(QThread::Priority::TimeCriticalPriority);

当然,你和我一样聪明,你就会知道这一点用都没有。

我以为的原因三

是否是TCP协议的原因呢?比如因为定时间隔时间太短(实际上我定时间隔为1s)导致基于拥塞窗口的拥塞控制发挥作用,直接导致传输变慢?

不可能啊,变慢能变慢到7秒8秒才发送到?况且我发送的数据字节数很少啊。


然后我想,可能跟QTcpSocket没关系,于是我写了一个简单的定时器程序。值得一提的是,写了两个,一个是将QTimer放在主线程,另一个是将QTimer放在子线程。

写了才发现,都有一样有问题的!不可能啊?就一个定时器程序怎么也有问题?

于是聪明的我开始思考到底哪里有问题。不是QTcpSocket的问题,不是QThread的问题,还有什么问题?

于是搜遍了某度、Gxxgle、Bxxg。

然后并没有找到我要的答案。

百思不得其解中,我发现一个问题:当我将窗口程序放置在桌面顶层时(我写的是Widget项目,虽然没有写任何窗口),程序是正常执行定时器操作的。于是我使用Qt Console Application创建方式重新写了一个计时器程序(使用QCoreApplication启动),值得惊喜的是,不管将程序放置在屏幕顶层还隐藏,该程序能正常运行!

我以为的原因四

经过上述实验,我感觉自己离知道真相进了一步,于是我大胆猜测:Qt程序不在屏幕顶层时,UI线程会随机地进入休眠。(因为命令行程序不采用UI线程为主线程,所以不会有影响)

于是我带着这个假设将定时器程序(使用QApplication启动的)放在Windows7上跑,结果让我震惊:居然是成功运行的。

我的最终回猜想

我发现了,macOS是内鬼吧。

于是我认为macOS操作系统下,非屏幕顶层的窗口程序主线程(UI线程)会被macOS不定时地休眠几秒钟。

ps.有大佬能解释一下这个现象吗?

2019年8月2日更新:

找到解决方法,就是在widget里加个定时器负责刷新widget(注意,要使用repaint方法,update方法被优化过),这样可以防止macOS不定时休眠进程。

转载于:https://my.oschina.net/StupidZhe/blog/3081573

你可能感兴趣的:(关于在macOS上运行Qt窗口程序遇到的坑)