• Qt_线程(待完善)


    Qt常见的创建线程的方式有两种:

    1. 继承QThread,在run函数中运行,start函数启动,这种方式创建的线程只有run函数中的部分,如果在run函数中调用其他的函数进行操作时,其他函数实际是在主函数中运行的。
    2. 使用moveToThread,这种方式主要是通过信号和槽的方式进行,只有槽的部分是属于线程的。

    优缺点:
    方法一:
    1. 线程中的对象必须在run函数中创建,线程的范围只在run函数中。原因:QThread以及它继承的类都是属于主线程的,tun函数是QThread开辟的线程,所以想要创建属于新的线程的实例就必须在run函数中进行初始化,实例化。
    3. 线程无法接收信号,只能发送信号。

    方法二:
    1. 比较灵活简洁
    2. 在线程中调用其他函数,函数还是属于线程的。
    第一种比较好理解和上手:

    #ifdef  _MSC_VER
    #if _MSC_VER >=1600 // VS2010版本号是1600
    #pragma execution_character_set("utf-8")
    #endif
    #endif
    
    #include "timethread.h"
    
    TimeThread::TimeThread()
    {
    }
    
    void TimeThread::run()
    {
        //    int num = 10;
        //    timer = new QTimer(this);
        //    connect(timer, SIGNAL(timeout()), this, SLOT(timeStop()));
        //    timer->start(1000 * num);
        //    qDebug() << "这个是线程";
    }
    
    void TimeThread::timeStop()
    {
    //    QMessageBox msgBox;
    //    msgBox.setText("The document has been modified.");
    //    msgBox.exec();
    //    timer->stop();
    }
    
    .h文件:
    #ifndef TIMETHREAD_H
    #define TIMETHREAD_H
    
    #include <QThread>
    #include <QDebug>
    #include <QTimer>
    #include <QMessageBox>
    
    class TimeThread: public QThread
    {
        Q_OBJECT
    public:
        TimeThread();
    //    explicit TimeThread();
    private slots:
        void timeStop();
    
    protected:
        void run();
    
    //private:
    //    QTimer *timer;
    };
    
    #endif // TIMETHREAD_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    另一种是

    #if _MSC_VER >=1600 //VS2010版本号是1600
        #pragma execution_character_set("utf-8")
    #endif
    
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow) {
        ui->setupUi(this);
        auto *worker = new Worker ;
        // 调用 moveToThread 将该任务交给 workThread
        worker->moveToThread(&workerThread);
        // operate 信号发射后启动线程工作
        connect(this, SIGNAL(operate(const int)), worker, SLOT(doWork(int)));
        // 该线程结束时销毁
        connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
        // 线程结束后发送信号,对结果进行处理
        connect(worker, SIGNAL(resultReady(int)), this, SLOT(handleResults(int)));
        // 启动线程
        workerThread.start();
        // 发射信号,开始执行
        qDebug() << "主线程发出线程执行的信号" ;
        qDebug() << "\t线程的ID:" << QThread::currentThreadId() << '\n' ;
        emit operate(0);
        for (int i = 0; i != 500; ++i) {
            qDebug() << "主线程的循环" << i;
        }
    }
    
    void MainWindow::handleResults(const int result) {
        qDebug() << "接受线程结束的信号" ;
        qDebug() << "\tCurrent thread ID: " << QThread::currentThreadId() << '\n' ;
        qDebug() << "\tThe last result is: " << result ;
    }
    
    MainWindow::~MainWindow() {
        qDebug() << "主线程的析构函数";
        workerThread.quit();
        workerThread.wait();
        delete ui;
    }
    
    
    Worker::Worker(QObject *parent) {
        qDebug() << "线程的构造函数";
    }
    
    Worker::~Worker() {
        qDebug() << "~Worker()" << "thread:" << QThread::currentThreadId();
    }
    
    void Worker::doWork(int parameter) {
        qDebug() << "接收到线程开始的信号,这个信号是主程序发出的" ;
        qDebug() << "\t线程的ID " << QThread::currentThreadId();
        // 循环一百万次
        for (int i = 0; i != 500; ++i) {
            qDebug() << "线程中的循环" << parameter;
            ++parameter ;
        }
        // 发送结束信号
        qDebug() << "\t线程运行结束\n" ;
        emit resultReady(parameter);
    }
    .h文件:
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    // 创建一个线程类,用来进行比较耗时的工作
    #include <QObject>
    #include <QDebug>
    #include <QThread>
    
    class Worker : public QObject {
        Q_OBJECT
    
    public:
        explicit Worker(QObject *parent = nullptr);
        ~Worker();
    
    public slots:
        // doWork 定义了线程要执行的操作
        void doWork(int parameter);
    
    signals:
        // 线程完成工作时发送的信号
        void resultReady(const int result);
    };
    
    QT_BEGIN_NAMESPACE
    namespace Ui {
        class MainWindow;
    }
    QT_END_NAMESPACE
    
    class MainWindow : public QMainWindow {
        Q_OBJECT
    
    public:
        MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
    public slots:
        // 处理子线程执行的结果
        static void handleResults(int result);
    
    signals:
        // 发送信号,触发线程
        void operate(const int);
    
    private:
        Ui::MainWindow *ui;
        QThread workerThread;
    };
    #endif // MAINWINDOW_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117

    附录:
    Qt connect的第5个参数:
    1、Qt::AutoConnection: 默认值,使用这个值则连接类型会在信号发送时决定。如果接收者和发送者在同一个线程,则自动使用Qt::DirectConnection类型。如果接收者和发送者不在一个线程,则自动使用Qt::QueuedConnection类型。

    2、Qt::DirectConnection:槽函数会在信号发送的时候直接被调用,槽函数运行于信号发送者所在线程。效果看上去就像是直接在信号发送位置调用了槽函数。这个在多线程环境下比较危险,可能会造成奔溃。

    3、Qt::QueuedConnection:槽函数在控制回到接收者所在线程的事件循环时被调用,槽函数运行于信号接收者所在线程。发送信号之后,槽函数不会立刻被调用,等到接收者的当前函数执行完,进入事件循环之后,槽函数才会被调用。多线程环境下一般用这个。

    4、Qt::BlockingQueuedConnection:槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。

    5、Qt::UniqueConnection:这个flag可以通过按位或(|)与以上四个结合在一起使用。当这个flag设置时,当某个信号和槽已经连接时,再进行重复的连接就会失败。也就是避免了重复连接。

  • 相关阅读:
    Tomcat中间件版本信息泄露
    EasyExcel使用实体类进行读操作和写操作
    【C++】一些特殊类的实现
    Unity Hub添加模块问题
    阿里云服务器上安装redis
    【Rust 笔记】14-集合(上)
    k8s metadata.labels,spec.template.metadata.labels,spec.selector 三者之间的关系。
    欧标插头EN50075测试项目
    http 请求 Cros 跨域问题记录(转)
    视觉SLAM14讲笔记-第7讲-视觉里程计1
  • 原文地址:https://blog.csdn.net/weixin_44248637/article/details/125446340