C++多线程编程with QT

1. QT中的线程类QThread

头文件要求: #include
qmake: QT += core
继承自: QObject

一个QThread管理程序中的一个线程,QThread执行run()后就启动线程。默认情况下,run()通过执行exec()启动事件循环,并且在线程内运行QT事件循环。

2.QT中开启线程的两种方法

推荐使用moveToThread方法开启线程,不用考虑安全问题。

2.1 对于已存在的类对象的成员函数——使用QObject::moveToThread().

这种方法将一个现有的某对象的成员函数移动到新建线程中执行。为实现此目标,需要对现有类进行更改。
优势:既有类中的成员函数改为槽函数后可以和任意线程中的signal连接,由于queued connections机制,这种连接是安全的。

class Worker : public QObject
{
    Q_OBJECT
//  #1 既有类需要增加槽函数 doWork,并emit <signal>
public slots:
    void doWork(const QString &parameter) {
        QString result;
        /* ... here is the expensive or blocking operation ... */
        emit resultReady(result);
    }
// #2 既有类需要增加信号函数,信号函数不用实现,但是应该跟之前emit的信号相同。
signals:
    void resultReady(const QString &result);
};

class Controller : public QObject
{
    Q_OBJECT
// #3 新建线程类对象,用来接收既有类
    QThread workerThread; 
public:
    Controller() {
// #4. 初始化既有类,通过moveToThread函数转移到之前新建的线程对象workerThread中
        Worker *worker = new Worker;
        worker->moveToThread(&workerThread);
// #5.1 connect线程结束信号和销毁槽函数
        connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
// #5.2 connect当前类的按钮点击之类的操作信号和既有类的耗时函数
        connect(this, &Controller::operate, worker, &Worker::doWork);
// #5.3 connect既有类的耗时函数相关的信号和当前类处理该信号的槽函数
        connect(worker, &Worker::resultReady, this, &Controller::handleResults);
// # 6. 启动线程,执行线程类的run()      
        workerThread.start();
    }
    ~Controller() {
// #7. 在当前类的析构函数中退出线程
        workerThread.quit();
        workerThread.wait();
    }
// #8.为当前类增加处理既有类信号的槽函数,该信号与线程doWork相关
public slots:
    void handleResults(const QString &);
signals:
    void operate(const QString &);
};

2.2 使代码在单独的线程中运行的另一种方法是子类QThread并重新实现‎‎运行‎‎()。安全性较低。

‎这种方法中,线程将在返回 run 函数后退出。除非调用‎‎exec‎‎(),否则线程中不会运行任何事件循环。‎

注意:QThread 实例位于实例化它的旧线程‎‎中‎‎,而不是位于调用‎‎run‎‎() 的新线程中。这意味着 QThread 的所有排队槽和‎‎调用的方法‎‎都将在旧线程中执行。因此,希望在新线程中调用槽的开发人员必须使用工作对象方法;新槽不应直接实现到子类化的 QThread 中。‎

‎与queued connections或调用的方法不同,直接在 QThread 对象上调用的方法将在调用该方法的线程中执行。子类化 QThread 时,请记住,构造函数在旧线程中执行,而‎‎run‎‎() 在新线程中执行。如果从两个函数访问成员变量,则从两个不同的线程访问该变量。检查这样做是否安全。‎

‎注意:‎‎与跨不同线程的对象进行交互时必须小心。作为一般规则,只能从创建线程调用函数‎‎广告对象本身(例如‎‎setPriority‎‎()),除非文档另有说明。有关详细信息‎‎,请参阅同步线程‎‎。‎

class WorkerThread : public QThread
{
    Q_OBJECT
    void run() override {
        QString result;
        /* ... here is the expensive or blocking operation ... */
        emit resultReady(result);
    }
signals:
    void resultReady(const QString &s);
};

void MyObject::startWorkInAThread()
{
    WorkerThread *workerThread = new WorkerThread(this);
    connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
    connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
    workerThread->start();
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ಥ_ಥLeerorz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值