使用 Qt 线程的最小示例?

Aar*_*onD 5 c++ qt multithreading

长话短说:

我一直在寻找 Qt 线程的简洁示例,我发现的只是复杂的“养眼的东西”,声称可以展示 QThread 的工作原理,但它们实在太多了,难以理解。

我接受了 Zen 的答案,因为他向我展示了我的尝试所缺少的确切内容,然后添加了我自己的答案作为我想看到的示例。单击此处跳至:/sf/answers/2419278571/

我原来的问题如下:


看来我一定错过了一些东西,但我似乎无法让这项工作像我认为的那样进行。我的完整应用程序需要有两个或三个线程,所有这些线程(几乎)一起启动并永远运行:

  • 图形用户界面
    • 在启动其他两个线程处理它们之前,从文件中加载一堆对象。
  • 实时处理器
    • 具有 TimeCriticalPriority 和周期性 QTimer“中断”,试图将 PC 用作比我开始时更强大的嵌入式系统。该项目一开始是完全嵌入的,但很快就变得过于复杂而无法管理。
  • USB HID 驱动程序
    • 连接到项目中仍嵌入的部分。

当然,核心功能是在实时处理线程中,其他两个只是调整其工作方式。因此,在实时处理器运行时,根据用户在 GUI 中的操作,会创建、修改和销毁处理对象,并且其中一些对象内的数据也由 USB 生成和消耗。

我一直在寻找如何在 Qt 中使用线程的示例,但我不断得到复杂的“养眼”类型的应用程序,这些应用程序使线程部分变得混乱。我尽力尝试解释它们并编写自己的代码,但我不断在 Qt 本身中遇到段错误,而且我的小型“游乐场”项目说我什至没有获得第二个线程:

#ifndef MAIN_H
#define MAIN_H

#include <QtWidgets>

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget* parent = 0);
    ~MainWindow() {}
private:
    QObject* mythingy;
private slots:
    void deleteObject(QObject* thingy);
};

class Worker : public QObject
{
    Q_OBJECT
public:
    Worker(QObject* thingy, QObject* parent = 0);
private:
    QObject* mythingy;
signals:
    void deleteObject(QObject* thingy);
private slots:
    void doWork();
};

#endif // MAIN_H

/***************
*** main.cpp ***
***************/
#include "main.h"
#include <QApplication>

int main(int argc, char* argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}



MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
{
    mythingy = new QObject(this);
    QThread* thisthread = this->thread();
    QThread* mainthread = QCoreApplication::instance()->thread();
    //breakpoint here to check thisthread and mainthread
    Worker* worker = new Worker(mythingy, this);
    connect(worker, SIGNAL(deleteObject(QObject*)), this, SLOT(deleteObject(QObject*)));
}

void MainWindow::deleteObject(QObject* thingy)
{
    QThread* thisthread = this->thread();
    QThread* mainthread = QCoreApplication::instance()->thread();
    //breakpoint here to check thisthread and mainthread
    delete thingy;
}



Worker::Worker(QObject* thingy, QObject* parent)
    : QObject(parent)
{
    mythingy = thingy;
    QThread* thread = new QThread(this);
    this->moveToThread(thread);

    //use a timer to allow the constructor to exit
    QTimer* timer = new QTimer(this);
    timer->setSingleShot(true);
    timer->start(1000);
    connect(timer, SIGNAL(timeout()), this, SLOT(doWork()));

    QThread* thisthread = this->thread();
    QThread* mainthread = QCoreApplication::instance()->thread();
    //breakpoint here to check thisthread and mainthread
    thread->start();
}

void Worker::doWork()
{
    QThread* thisthread = this->thread();
    QThread* mainthread = QCoreApplication::instance()->thread();
    //breakpoint here to check thisthread and mainthread
    deleteObject(mythingy);
}
Run Code Online (Sandbox Code Playgroud)

如果有人可以根据我对项目的描述,发布一个如何正确执行 QThreads 的示例,并且尽可能少地混乱(如果可能的话,最好比我的短),我将不胜感激。


编辑:

根据 Zen 的回答,这似乎也有效:

MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
{
    mythingy = new QObject(this);
    QThread* thisthread = this->thread();
    QThread* mainthread = QCoreApplication::instance()->thread();
    Worker* worker = new Worker(mythingy, this);
}

Worker::Worker(QObject* thingy, QObject* parent)
    : QObject(0)    //no real parent, so we can move to a different thread
{
    mythingy = thingy;

    QTimer* timer = new QTimer(this);
    timer->setSingleShot(true);
    timer->start(1000);
    connect(timer, SIGNAL(timeout()), this, SLOT(doWork()));

    QThread* thread = new QThread(parent);
    this->moveToThread(thread);
    thread->start();
}

void Worker::doWork()
{
    QThread* thisthread = this->thread();
    QThread* mainthread = QCoreApplication::instance()->thread();
    delete mythingy;
}
Run Code Online (Sandbox Code Playgroud)

仍在构造函数内移动自己,现在直接删除对象,而不是告诉所有者的线程来执行此操作。(请记住,在完整的项目中,所有者已经将对象标记为删除,但没有实际这样做,因为其他线程可能正在使用它)

有什么问题吗?

Zen*_*Zen 1

1.您不能与父对象一起移动对象。因此Worker* worker = new Worker(mythingy, this);,您应该使用Worker* worker = new Worker(mythingy);
2。您不能为位于不同线程中的父级创建子级。

MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
{
    mythingy = new QObject(this);
    QThread* thisthread = this->thread();
    QThread* mainthread = QCoreApplication::instance()->thread();
    //breakpoint here to check thisthread and mainthread
    //*****************
    Worker* worker = new Worker(mythingy);
    QThread* thread = new QThread();
    worker->moveToThread(thread);
    thread->start();
    //*****************
    connect(worker, SIGNAL(deleteObject(QObject*)), this, SLOT(deleteObject(QObject*)));
}

Worker::Worker(QObject* thingy, QObject* parent)
    : QObject(parent)
{
    mythingy = thingy;
//    QThread* thread = new QThread(this);
//    this->moveToThread(thread);

    //use a timer to allow the constructor to exit
    QTimer* timer = new QTimer(this);
    timer->setSingleShot(true);
    timer->start(1000);
    connect(timer, SIGNAL(timeout()), this, SLOT(doWork()));

//    QThread* thisthread = this->thread();
//    QThread* mainthread = QCoreApplication::instance()->thread();
    //breakpoint here to check thisthread and mainthread
//    thread->start();
}
Run Code Online (Sandbox Code Playgroud)

对象的槽总是由它所在的线程执行。因此,由于您从未移动过MainWindow,因此无需在 中检查其线程MainWindow::deleteObject。例如:

Worker* worker = new Worker(mythingy);
QThread* thread = new QThread();
worker->moveToThread(thread);
thread->start();

//wrong: directly invoking doWork in mainthread    
worker->doWork();

//correct: through signal-slot mechanics
connect(this, SIGNAL(startWork()), worker, SLOT(doWork()));
Run Code Online (Sandbox Code Playgroud)