QT中创建线程的几种方法(QThread的使用示例)

QT 创建子线程

QT 创建子线程有几种方法:

  1. 创建子类,继承自QThread类,重写QThread::run()函数,调用子类的QThread::start()即可在子线程中执行。
  2. QThread::create()创建线程指针对象,调用指针线程的QThread::start()即可在子线程中执行。
  3. 调用QObject::moveToThread()QThread类对象,通过信号和槽触发执行子类处理函数。

注意:

  • moveToThread方法必须使用信号和槽的触发方式,否则依然在调用线程中执行。
  • 线程的销毁注意子类资源的释放

代码示例

  • .h
class Thread : public QThread {
    Q_OBJECT
public:
    explicit Thread(QObject *parent = nullptr);
    virtual ~Thread();
protected:
    virtual void run() override;
};
class Worker : public QObject{
    Q_OBJECT
public:
    explicit Worker(QObject *parent = nullptr);
    virtual ~Worker();
    void doWorker();
    virtual bool event(QEvent *event) override;
signals:
    void start();
};
  • .cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
    ui->setupUi(this);
    // 防止输入法中间输出内容
    QTimer*timer = new QTimer;
    connect(timer, &QTimer::timeout, this, [this, timer](){
        timer->stop();
        qDebug() << "\n====\n";
        this->ThreadTest();
    });
    timer->start(1000);
}

MainWindow::~MainWindow() { delete ui; }

#define LOG_THREAD_FUNC qDebug().noquote().nospace() << "[0x" << (void*) QThread::currentThreadId() << "] : " << __PRETTY_FUNCTION__
#define LOG_THREAD      qDebug().noquote().nospace() << "[0x" << (void*) QThread::currentThreadId() << "] : "
#define SLEEP_SECONES   3

static bool willRun = true;  // THREAD_MOVE_TO_THREAD 示例中, Thread 作为承接线程会重复输出,需要手动跳过。

auto thread_doworker_slots = [](){
    if(!willRun) { return; }
    LOG_THREAD << "run in.";
    QThread::sleep(SLEEP_SECONES);
    LOG_THREAD << "run out.";
};
auto thread_started_slots  = [](){ LOG_THREAD << "started."; };
auto thread_finished_slots = [](){
    LOG_THREAD << "finished in.";
    QThread::currentThread()->deleteLater(); // ok,但是不会析构子类资源
    // thread->deleteLater();   // ok  // 传入线程对象较为麻烦,暂时不用该方法
    // sender()->deleteLater(); // crash
    LOG_THREAD << "finished out.";
};

Thread::Thread(QObject *parent) : QThread(parent) { LOG_THREAD_FUNC; }
Thread::~Thread()  { LOG_THREAD_FUNC; }
void Thread::run() { thread_doworker_slots(); }

Worker::Worker(QObject *parent) : QObject(parent) { LOG_THREAD_FUNC; }
Worker::~Worker() { LOG_THREAD_FUNC; }
void Worker::doWorker() {
    LOG_THREAD << "Worker in.";
    QThread::sleep(SLEEP_SECONES);
    LOG_THREAD << "Worker out.";
}
bool Worker::event(QEvent *event) {
    switch (event->type()) {
    case QEvent::ThreadChange:
        LOG_THREAD_FUNC << " case QEvent::ThreadChange.";
        break;
    default:
        break;
    }
    return QObject::event(event);
}


void MainWindow::ThreadTest() {
    // 使用指针对象可立即返回,并在执行结束后调用 deleteLater 进行资源销毁。  // 调用 QThread::wait 会阻塞返回
    //    thread->wait : [main]Thread -> [thread]run in -> [thread]run out                  -> [main]started.
    //                   -> [main]finished in. -> [main]finished out. -> [main]~Thread -> [QWidget]show;
    // no thread->wait : [main]Thread -> [thread]run in -> [main]started.  -> [QWidget]show -> [thread]run out
    //                   -> [main]finished in. -> [main]finished out. -> [main]~Thread                 ;

    enum {
        THREAD_OBJECT_WAIT,               // 不推荐 // 创建线程对象,在函数中等待执行结果。失去创建线程的意义。
        THREAD_POINT_DELETE_LATE,         // 不推荐 // 创建线程指针对象,调用线程默认的deleteLater销毁线程指针,可销毁子类资源。
        THREAD_POINT_DELETE_SLOT_PUBLIC,  // 不推荐 // 创建线程指针对象,调用公共自定义函数销毁线程资源  // 暂时无法销毁子类资源
        THREAD_POINT_DELETE_SLOT_SELF,    // 推荐  // 创建线程指针对象,调用专用自定义函数销毁线程资源,可销毁子类资源。
        THREAD_CREATE,                    // 推荐  // 调用 create 创建线程对象
        THREAD_MOVE_TO_THREAD             // 推荐  // 调用 moveToThread 及信号和槽,由子进程执行操作
    };
    int test = 30;
    switch (test) {
        // Thread 对象,非指针,只能函数内等待销毁
    case THREAD_OBJECT_WAIT: {
        // 线程的生命周期需要在函数内销毁,会阻塞函数运行
        Thread thread;   // 创建对象
        thread.start();  // 启动执行
        thread.wait();   // 等待结束,否则崩溃  // 没有detach函数
        // output:
        // [0x0x6d2c] : Thread::Thread(QObject*)
        // [0x0x1678] : run in.
        // [0x0x1678] : run out.
        // [0x0x6d2c] : virtual Thread::~Thread()
    }
    break;
        // Thread 指针,立即返回
    case THREAD_POINT_DELETE_LATE: {
        Thread *thread = new Thread;
        connect(thread, &Thread::started , thread, thread_started_slots);
        connect(thread, &Thread::finished, thread, &Thread::deleteLater);      // 会调用析构
        thread->start();
        // output:
        // [0x0x4858] : Thread::Thread(QObject*)
        // [0x0x6afc] : run in.
        // [0x0x4858] : started.
        // [0x0x6afc] : run out.
        // [0x0x4858] : virtual Thread::~Thread()
    }
    break;
    case THREAD_POINT_DELETE_SLOT_PUBLIC: {
        qWarning().noquote().nospace() << "注意:该示例中传入的为父类,因此不会调用子类的析构函数。";
        Thread *thread = new Thread;
        connect(thread, &Thread::started , thread, thread_started_slots);
        connect(thread, &Thread::finished, thread, thread_finished_slots);    // 不会调用析构(未传入子类对象)
        thread->start();
        // output:
        // [0x0x42b8] : Thread::Thread(QObject*)
        // [0x0x6374] : run in.
        // [0x0x42b8] : started.
        // [0x0x6374] : run out.
        // [0x0x42b8] : finished in.
        // [0x0x42b8] : finished out.
    }
    break;
    case THREAD_POINT_DELETE_SLOT_SELF: {
        Thread *thread = new Thread;
        connect(thread, &Thread::started , thread, thread_started_slots);
        connect(thread, &Thread::finished, thread, [thread](){
            LOG_THREAD << "finished in.";
            thread->deleteLater();  // ok // 会调用析构
            LOG_THREAD << "finished out.";
        });
        thread->start();
        // output:
        // [0x0x70a0] : Thread::Thread(QObject*)
        // [0x0x4e78] : run in.
        // [0x0x70a0] : started.
        // [0x0x4e78] : run out.
        // [0x0x70a0] : finished in.
        // [0x0x70a0] : finished out.
        // [0x0x70a0] : virtual Thread::~Thread()
    }
    break;
        // Thread::create
    case THREAD_CREATE: {
        QThread* thread = QThread::create(thread_doworker_slots);
        connect(thread, &Thread::started , thread, thread_started_slots);
        connect(thread, &Thread::finished, thread, [thread](){
            LOG_THREAD << "finished in.";
            thread->deleteLater();  // ok // 会调用析构
            LOG_THREAD << "finished out.";
        });
        thread->start();
        // output:
        // [0x0x5640] : run in.
        // [0x0x7ba8] : started.
        // [0x0x5640] : run out.
        // [0x0x7ba8] : finished in.
        // [0x0x7ba8] : finished out.
    }
    break;
    case THREAD_MOVE_TO_THREAD: {
        //  移动到主线程 : myObject->moveToThread(QApplication::instance()->thread());
        willRun = false;
        Thread*thread = new Thread;
        connect(thread, &Thread::started , thread, thread_started_slots);
        connect(thread, &Thread::finished, thread, [thread](){
            LOG_THREAD << "finished in.";
            thread->deleteLater();  // ok // 会调用析构
            LOG_THREAD << "finished out.";
        });
        Worker*worker  = new Worker;
        LOG_THREAD_FUNC << " moveToThread start.";
        LOG_THREAD_FUNC << " moveToThread " << (worker->moveToThread(thread) ? "success." : "false.");
        thread->start();  // 没有开始执行实际内容
        LOG_THREAD_FUNC << " before doWorker.";
        // worker->doWorker();  // 必须通过信号和槽的方式调用处理函数,处理函数才能在子线程中执行
        connect(worker, &Worker::start, worker, &Worker::doWorker);
        worker->start();
        willRun = true;
        // output:
        // [0x0x73c8] : Thread::Thread(QObject*)
        // [0x0x73c8] : Worker::Worker(QObject*)
        // [0x0x73c8] : void MainWindow::ThreadTest() moveToThread start.
        // [0x0x73c8] : virtual bool Worker::event(QEvent*) case QEvent::ThreadChange.
        // [0x0x73c8] : void MainWindow::ThreadTest() moveToThread success.
        // [0x0x73c8] : void MainWindow::ThreadTest() before doWorker.
        // [0x0x7728] : run in.
        // [0x0x73c8] : started.
        // [0x0x7728] : run out.
        // [0x0x73c8] : finished in.
        // [0x0x73c8] : finished out.
        // [0x0x73c8] : virtual Thread::~Thread()
    }
    break;
    default:
        LOG_THREAD_FUNC << " switch case default.";
        break;
    }
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值