Qt processEvents - 解决线程中事件阻塞(如槽函数被阻塞)

百度了一会,发现没太有文字讲这件事情,因此整理成文字记录一下。


processEvents介绍

长时间运行的操作可以调用processEvents() 保持应用程序响应能力。

void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents)
根据指定的条件为调用线程处理一些待处理事件flags

void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags, int ms)
处理调用线程的待处理事件(Pending Events)达ms毫秒,或直到没有更多事件需要处理,以较短者为准。

关于ms参数的解释(来自GPT-3.5):

  • 如果正在处理事件的时间超过了指定的时间限制 ms,processEvents 函数仍然会等待事件处理完成,然后返回。
  • 如果事件处理完成前的时间限制 ms 达到了,那么 processEvents 函数将立即返回,即使事件队列中仍有待处理的事件。
  • 此处不太好验证,官方文档也没详写,经博主本人分析,gpt解释的合理

注意:

调用此函数时,线程切换去处理事件时,之前正在做的操作就被阻塞了,直到待处理事件完成。


问题代码及解决方法

问题代码:线程中有死循环,导致没有机会处理事件,执行槽函数。

解决方法:放开注释。使用QCoreApplication::processEvents();

// Work类的槽函数:

// 先触发这个槽函数,里面有while循环,会卡住线程
void Worker::doWork() 
{
    qDebug() << __FUNCTION__ << " Thread ID: " << QThread::currentThreadId() << "\n";

    // 循环10次,每次1s
    int i = 1;
    while (i < 10)
    {
        i++;
        Sleep(1000);
        qDebug() << "second : " << i << " s\n";

        //QCoreApplication::processEvents();    // 
    }
}

// 再触发这个槽函数,会因为线程在做while循环,没有机会得到执行
void Worker::doWork2() 
{
    qDebug() << __FUNCTION__ << " Thread ID: " << QThread::currentThreadId();
}

----------------------------------------------------------------------------------------------------------

// Main函数中的代码
auto *worker = new Worker;
_workerThread = new QThread(this);
worker->moveToThread(_workerThread);    // worker的槽函数都在_workerThread线程中执行

connect(this, SIGNAL(operate()), worker, SLOT(doWork(int)));
connect(this, SIGNAL(operate2()), worker, SLOT(doWork2(int)));
    
// 启动线程
_workerThread->start();

emit operate();    // 先让线程中的while循环跑起来
emit operate2();   // 再触发doWork2槽函数,但是因为子线程中doWork在while循环,
                   // 此事件没有机会被处理,直至while循环结束才得到doWork2执行的机会。

结果1:
注掉QCoreApplication::processEvents(); 阻塞情况:

Worker::doWork  Thread ID:  0x4260 

second :  2  s
second :  3  s
second :  4  s
second :  5  s
second :  6  s
second :  7  s
second :  8  s
second :  9  s

Worker::doWork2  Thread ID:  0x4260

结果2:
放开注释 QCoreApplication::processEvents(); 解决阻塞问题后:

Worker::doWork  Thread ID:  0x4260 

second :  2  s

Worker::doWork2  Thread ID:  0x4260        // 执行processEvents时,如果有事件被阻塞了,立刻执行其槽函数

second :  3  s
second :  4  s
second :  5  s
second :  6  s
second :  7  s
second :  8  s
second :  9  s