Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在Qt中使用多线程时的事件循环和信号槽处理_C++_Multithreading_Qt_Event Loop_Signals Slots - Fatal编程技术网

C++ 在Qt中使用多线程时的事件循环和信号槽处理

C++ 在Qt中使用多线程时的事件循环和信号槽处理,c++,multithreading,qt,event-loop,signals-slots,C++,Multithreading,Qt,Event Loop,Signals Slots,我在使用QThreads时遇到了一些问题,这使得我在找到正确的组合之前先研究了不同的组合。然而,当涉及到事件循环和信号槽处理时,我仍然不能完全理解下面所示的四种情况中到底发生了什么 我在“输出”部分添加了一些注释,但正如您所看到的,我不确定我关于导致观察到的行为的假设是否正确。另外,我不确定案例3是否可以在实际代码中使用。这是我的测试代码(只有main.cpp在每种情况下有所不同): 工人h: 输出-在a.exec()调用slot1和slot2(?-使用主事件循环?): main.cpp(案例2

我在使用
QThreads
时遇到了一些问题,这使得我在找到正确的组合之前先研究了不同的组合。然而,当涉及到事件循环和信号槽处理时,我仍然不能完全理解下面所示的四种情况中到底发生了什么

我在“输出”部分添加了一些注释,但正如您所看到的,我不确定我关于导致观察到的行为的假设是否正确。另外,我不确定
案例3
是否可以在实际代码中使用。这是我的测试代码(只有
main.cpp
在每种情况下有所不同):

工人h:

输出-在
a.exec()调用
slot1
slot2
(?-使用主事件循环?):

main.cpp(案例2-
workerManager
移动到单独的线程,但线程未启动):

main.cpp(案例3-
workerManager
移动到单独的线程,线程已启动,但通过
workerManager->process()调用
workerManager::process()
):

main.cpp(案例4-
workerManager
移动到单独的线程,线程已启动,但使用
start()
来自
线程的信号调用
workerManager::process()
):


感谢您的澄清。

您得到的所有结果都是完全正确的。我将尝试解释这是如何工作的

事件循环是Qt代码中处理系统和用户事件的内部循环。调用
a.exec()
时,主线程的事件循环启动。另一个线程的事件循环由
QThread::run
的默认实现启动

当Qt决定处理事件的时间时,它执行其事件处理程序。当事件处理程序工作时,Qt没有机会处理任何其他事件(除非由
QApplication::processEvents()
或其他一些方法直接给出)。一旦事件处理程序完成,控制流返回到事件循环,Qt可以执行另一个处理程序来处理另一个事件

信号和插槽与Qt术语中的事件和事件处理程序不同。但插槽由事件循环处理的方式有点类似。如果代码中有控制流(例如在<代码>主< /COD>函数),那么可以立即执行任何槽,就像任何其他C++函数一样。但当Qt这样做时,它只能从事件循环中完成。应该注意的是,信号总是立即发送,而时隙执行可能会延迟

现在让我们看看每种情况下会发生什么

案例1
WorkerManager::process
直接在程序启动时执行。启动新线程,并在新线程中立即执行
Worker::process
WorkerManager::process
继续执行,直到Worker完成,冻结主线程中的所有其他操作(包括插槽处理)。在
WorkerManager::process
完成后,控制流转到
QApplication::exec
。Qt建立到另一个线程的连接,接收关于插槽调用的消息,并随后调用所有这些消息

案例2 默认情况下,Qt在该对象所属的线程中执行对象的插槽。主线程不会执行WorkerManager的插槽,因为它属于另一个线程。但是,此线程从未启动。它的事件循环永远不会结束。调用
slot1
slot2
将永远留在Qt的队列中,等待您启动线程。悲惨的故事

案例3 在这种情况下,
WorkerManager::process
在主线程中执行,因为您直接从主线程调用它。同时,
WorkerManager的线程启动。它的事件循环被启动并等待事件
WorkerManager::process
启动
Worker
的线程并在其中执行
Worker::exec
<代码>工作者
开始向
工作者管理者
发送信号
WorkerManager的线程几乎立即开始执行适当的插槽。此时,同时执行
WorkerManager::slot2
WorkerManager::process
似乎有些尴尬。但至少在
WorkerManager
是线程安全的情况下,这是非常好的。在
Worker
完成后不久,
WorkerManager::process
完成,执行
a.exec()
,但没有太多要处理的内容

案例4 Main函数只需启动
WorkerManager
的线程,并立即转到
a.exec()
,从而将
end
作为输出的第一行
a.exec()
处理某些内容并确保程序执行,但不执行WorkerManager的插槽,因为它属于另一个线程
WorkerManager::process
在其事件循环的
WorkerManager
线程中执行
Worker
的线程启动,
Worker::process
开始从
Worker
的线程向
WorkerManager
的线程发送信号。不幸的是,后者正忙于执行
WorkerManager::process
。当
Worker
完成时,
WorkerManager::process
也完成,并且
WorkerManager
的线程立即执行所有排队的插槽

代码中最大的问题是
usleep
和无限循环。在使用Qt时,几乎不应该使用这些。我知道在
Worker::process
中睡眠只是一些实际计算的占位符。但您应该从
WorkerManager
中删除睡眠和无限循环。使用
WorkerManager::slot1
检测
Worker
的终止。如果开发GUI应用程序,则无需将
WorkerManager
移动到另一个线程。它的所有方法(无睡眠)都将快速执行,并且不会冻结GUI

#include <QObject>
#include <QDebug>
#include <QThread>

class Worker : public QObject
{
    Q_OBJECT
public:
    explicit Worker(QObject *parent = 0) { this->isRunning_ = false;}
    bool isRunning() const { return isRunning_; }

signals:
    void processingFinished();
    void inProgress();

public slots:
    void process()
    {
        this->isRunning_ = true;
        qDebug() << this << "processing started";
        for (int i = 0; i < 5; i++)
        {
            QThread::usleep(1000);
            emit this->inProgress();
        }
        qDebug() << this << "processing finished";
        this->isRunning_ = false;
        emit this->processingFinished();
    }

private:
    bool isRunning_;
};
#include "worker.h"

class WorkerManager : public QObject
{
    Q_OBJECT
public:
    explicit WorkerManager(QObject *parent = 0) :
        QObject(parent) {}

public slots:
    void process()
    {
        QThread *thread = new QThread();
        Worker  *worker = new Worker();

        connect(thread,SIGNAL(started()),worker,SLOT(process()));
        connect(worker,SIGNAL(processingFinished()),this,SLOT(slot1()));
        connect(worker,SIGNAL(inProgress()),this,SLOT(slot2()));
        worker->moveToThread(thread);

        qDebug() << "starting";
        thread->start();
        QThread::usleep(500);
        while(worker->isRunning()) { }
        qDebug() << "finished";
    }

    void slot1() { qDebug() << "slot1"; }
    void slot2() { qDebug() << "slot2"; }
};
#include <QCoreApplication>
#include "workermanager.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    WorkerManager* workerManager = new WorkerManager;    
    workerManager->process();
    qDebug() << "end";
    return a.exec();
}
starting 
Worker(0x112db20) processing started 
Worker(0x112db20) processing finished 
finished 
end
slot2 
slot2 
slot2 
slot2 
slot2 
slot1 
#include <QCoreApplication>
#include "workermanager.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    WorkerManager* workerManager = new WorkerManager;
    QThread *thread = new QThread();   
    workerManager->moveToThread(thread);       
    workerManager->process();
    qDebug() << "end";
    return a.exec();
}
starting 
Worker(0x112db20) processing started 
Worker(0x112db20) processing finished 
finished 
end
#include <QCoreApplication>
#include "workermanager.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    WorkerManager* workerManager = new WorkerManager;
    QThread *thread = new QThread();   
    workerManager->moveToThread(thread); 
    thread->start();     
    workerManager->process();
    qDebug() << "end";
    return a.exec();
}
starting 
Worker(0x197bb20) processing started 
slot2 
slot2 
slot2 
slot2 
Worker(0x197bb20) processing finished 
finished 
end 
slot2 
slot1 
#include <QCoreApplication>
#include "workermanager.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    WorkerManager* workerManager = new WorkerManager;
    QThread *thread = new QThread();    
    workerManager->moveToThread(thread);
    QObject::connect(thread,SIGNAL(started()),workerManager,SLOT(process()));
    thread->start();
    qDebug() << "end";
    return a.exec();
}
end 
starting 
Worker(0x7f1d700013d0) processing started 
Worker(0x7f1d700013d0) processing finished 
finished 
slot2 
slot2 
slot2 
slot2 
slot2 
slot1