• (十七)线程,connect的第五个参数


    采用多线程,将需要处理的后台数据放入子线程,为了能够跨线程调用,一种方法是使用类似线程锁对线程进行保护,另外一种方法使用Qt的信号槽机制。Qt的信号槽机制采用connect函数进行连接,connect函数其实是有第五个参数的,但这个参数往往在多线程调用中才会用到:

    connect(Sender,SIGNAL(signal),Receiver,SLOT(slot),Qt::DirectConnection);  

    1
    第五个参数代表槽函数在哪个线程中执行 :
    1)自动连接(AutoConnection),默认的连接方式,如果信号与槽,也就是发送者与接受者在同一线程,等同于直接连接;如果发送者与接受者处在不同线程,等同于队列连接。
    2)直接连接(DirectConnection),当信号发射时,槽函数立即直接调用。无论槽函数所属对象在哪个线程,槽函数总在发送者所在线程执行,即槽函数和信号发送者在同一线程
    3)队列连接(QueuedConnection),当控制权回到接受者所在线程的事件循环时,槽函数被调用。槽函数在接受者所在线程执行,即槽函数与信号接受者在同一线程
    4)锁定队列连接(QueuedConnection)
    Qt::BlockingQueuedConnection:槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。
    5)单一连接(QueuedConnection)
    Qt::UniqueConnection:这个flag可以通过按位或(|)与以上四个结合在一起使用。当这个flag设置时,当某个信号和槽已经连接时,再进行重复的连接就会失败。也就是避免了重复连接
    如果槽函数中有耗时操作,比如说while循环,主线程的信号子线程是不会响应的,除非使用直接连接(DirectConnection),connect(this, &Controller::kill, worker, &Worker::stopWork, Qt::DirectConnection);,此时,槽函数工作于主线程。
    下面是一个简单的多线程例子: (Qt有两种多线程的方法,其中一种是继承QThread的run函数,另外一种是把一个继承于QObject的类转移到一个Thread里。 Qt4.8之前都是使用继承QThread的run这种方法,但是Qt4.8之后,Qt官方建议使用第二种方法。两种方法区别不大,用起来都比较方便,但继承QObject的方法更加灵活。)

    QT4.7版本以前线程的使用

    #include "mywidget.h"
    #include "ui_mywidget.h"
    
    MyWidget::MyWidget(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::MyWidget)
    {
        ui->setupUi(this);
        mytimer = new QTimer(this);
        myt = new MyThread(this);
        connect(mytimer,&QTimer::timeout,this,[=](){
           static int num = 0;
           ui->lcdNumber->display(num++);
        });
    
        connect(ui->begin, &QPushButton::clicked, this, [=](){
            if(mytimer->isActive() == true)
            {
                return;
            }
            // 启动定时器
            mytimer->start(500); // ms
    
            // 启动线程
            myt->start();
        });
    
        connect(myt,&MyThread::sigDone,mytimer,&QTimer::stop);
    }
    
    MyWidget::~MyWidget()
    {
        delete ui;
    }
    MyWidget.cpp
    #ifndef MYWIDGET_H
    #define MYWIDGET_H
    
    #include <QWidget>
    #include <QTimer>
    #include "mythread.h"
    
    namespace Ui {
    class MyWidget;
    }
    
    class MyWidget : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit MyWidget(QWidget *parent = nullptr);
        ~MyWidget();
    
    private:
        Ui::MyWidget *ui;
        QTimer *mytimer;
        MyThread* myt;
    };
    
    #endif // MYWIDGET_H
    MyWidget.h
    #include "mythread.h"
    
    MyThread::MyThread(QObject *parent) : QThread(parent)
    {
    
    }
    
    void MyThread::run()
    {
        // 复杂的操作
        sleep(5);
        emit sigDone();
    }
    MyThread.cpp
    #ifndef MYTHREAD_H
    #define MYTHREAD_H
    
    #include <QObject>
    #include <QThread>
    
    class MyThread : public QThread
    {
        Q_OBJECT
    public:
        explicit MyThread(QObject *parent = nullptr);
    protected:
        void run(); // 入口函数 -- 需要start()启动
    
    signals:
        void sigDone();
    public slots:
    };
    
    #endif // MYTHREAD_H
    MyThread.h

     

    QT4.7版本之后线程的使用

        /* 多线程使用注意事项:
         * 1. 业务对象, 构造的时候不能指定父对象
         * 2. 子线程中不能处理ui窗口(ui相关的类)
         * 3. 子线程中只能处理一些数据相关的操作, 不能涉及窗口
        */
        /* connect 的第 5 参数
         * 1. 自动连接 -- 默认
         *      多线程 -- 指定队列连接
         *      单线程 -- 指定直接连接
         * 2. 队列连接 -- 多线程
         *      槽函数在信号接受者(receiver)所在的线程中执行
         * 3. 直接连接 -- 单线程
         *      信号和槽函数在同一个线程中执行
        */
    #include "mywidget.h"
    #include "ui_mywidget.h"
    
    MyWidget::MyWidget(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::MyWidget)
    {
        ui->setupUi(this);
        mytimer  = new QTimer(this);
        // 1. 业务对象
        mywork = new MyWork();
        // 2. 子线程类
        pthread = new QThread(this);
        // 3. 移动业务对象到子线程
        mywork->moveToThread(pthread);
    
        // 5. 子线程工作
        connect(this, &MyWidget::sigWorking, mywork, &MyWork::doMyWork);
    
    
        connect(ui->begin, &QPushButton::clicked, this, &MyWidget::slotStart);
        connect(ui->stop, &QPushButton::clicked, this, &MyWidget::slotStop);
        // 定时器
        connect(mytimer, &QTimer::timeout, this, &MyWidget::slotTimeout);
    
        connect(this,&MyWidget::destroyed, this, &MyWidget::slotCloseThread);
    }
    
    MyWidget::~MyWidget()
    {
        delete ui;
    }
    
    void MyWidget::slotStart()
    {
        if(mytimer->isActive() == true)
        {
            return;
        }
        if(pthread->isRunning())
        {
            return;
        }
        mytimer->start(500);
        // 4. 启动子线程
        pthread->start();
    
        // 发信号, 让子线程工作
        emit sigWorking();
    }
    
    void MyWidget::slotStop()
    {
        mytimer->stop();
    }
    
    void MyWidget::slotTimeout()
    {
        static int num = 0;
        ui->lcdNumber->display(num++);
    }
    
    void MyWidget::slotCloseThread()
    {
        mywork->setFlage(true);
    
        pthread->quit();
        pthread->wait();    // 等待线程手头上的工作处理完成
    }
    mywidget.cpp
    #ifndef MYWIDGET_H
    #define MYWIDGET_H
    
    #include <QWidget>
    #include <QTimer>
    #include "mywork.h"
    #include <QThread>
    
    namespace Ui {
    class MyWidget;
    }
    
    class MyWidget : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit MyWidget(QWidget *parent = nullptr);
        ~MyWidget();
        // 开始按钮
        void slotStart();
        // 关闭按钮
        void slotStop();
        // 定时器
        void slotTimeout();
        // 关闭线程
        void slotCloseThread();
    
    signals:
        void sigWorking();
    
    private:
        Ui::MyWidget *ui;
        QTimer* mytimer;
        MyWork* mywork;
        QThread* pthread;
    };
    
    #endif // MYWIDGET_H
    mywidget.h
    #include "mywork.h"
    #include <QDebug>
    
    MyWork::MyWork(QObject *parent) : QObject(parent)
    {
        isStop = false;
    }
    
    void MyWork::doMyWork()
    {
        while(!isStop)
        {
            // 操作
            QThread::sleep(1);  // 当前线程处理操作用了1s
            // 每执行一次循环发一次信号
            emit sigDone();
            qDebug() << QThread::currentThread() << "sub thread";
            // QMessageBox::aboutQt(NULL);
            if(isStop)
            {
                break;
            }
        }
    }
    
    void MyWork::setFlage(bool bl)
    {
        isStop = bl;
    }
    mywork.cpp
    #ifndef MYWORK_H
    #define MYWORK_H
    
    #include <QObject>
    #include <QThread>
    
    class MyWork : public QObject
    {
        Q_OBJECT
    public:
        explicit MyWork(QObject *parent = nullptr);
        // 业务处理函数
        void doMyWork();
    
        void setFlage(bool bl);
    
    signals:
        void sigDone();
    
    public slots:
    private:
        bool isStop;
    
    };
    
    #endif // MYWORK_H
    mywork.h

  • 相关阅读:
    [LeetCode] 852. Peak Index in a Mountain Array
    [LeetCode] 221. Maximal Square
    [LeetCode] 260. Single Number III
    [LeetCode] 532. K-diff Pairs in an Array
    [LeetCode] 1417. Reformat The String
    [LeetCode] 621. Task Scheduler
    [LeetCode] 454. 4Sum II
    [LeetCode] 18. 4Sum
    [LeetCode] 369. Plus One Linked List
    [LeetCode] 380. Insert Delete GetRandom O(1)
  • 原文地址:https://www.cnblogs.com/xiangtingshen/p/10793303.html
Copyright © 2020-2023  润新知