QT学习-线程

应用程序在某些情况下需要处理比较复杂的逻辑, 如果只有一个线程去处理,就会导致窗口卡顿,无法处理用户的相关操作,这种情况下就需要使用多线程。

Qt中使用多线程需要注意:

  1. Qt的默认线程为窗口线程(主线程)负责窗口事件处理或窗口控件数据的更新
  2. 子线程负责后台的业务逻辑,子线程不能对窗口对象做任何操作,这些事交给窗口线程;
  3. 主线程和子线程之间如果进行数据的传递,需要使用信号槽机制

QT中使用线程必须使用的QThread类,而QThread的线程类常见的使用的方法如下所示:

QThread(QObject *parent = nullptr)
virtual~QThread()
QAbstractEventDispatcher *eventDispatcher() const
void

exit(int returnCode = 0)

退出线程的工作函数

bool

isFinished() const

判断线程中的任务是否处理完毕

bool

isInterruptionRequested() const

bool

isRunning() const

判断线程中的任务是否正在执行任务

int

loopLevel() const

返回线程的当前事件循环级别。

QThread::Priority

priority() const

获取当前线程优先级

void

requestInterruption()

此函数可用于使长时间运行的任务完全可中断。从不检查或操作此函数返回的值是安全的,但建议在长时间运行的函数中定期这样做。注意不要太频繁地调用它,以保持低开销。

void

setEventDispatcher(QAbstractEventDispatcher *eventDispatcher)

void

setPriority(QThread::Priority priority)

设置当前线程优先级

void

setStackSize(uint stackSize)

uint

stackSize() const

bool

wait(QDeadlineTimer deadline = QDeadlineTimer(QDeadlineTimer::Forever))

调用线程退出函数之后,线程不会马上退出,因为当前任务可能没有完成

bool

wait(unsigned long time)

 

Public Slots

void

quit()

告诉线程的事件循环退出,返回代码0(成功)。相当于调用QThread::exit(0)。
如果线程没有事件循环,则此函数不执行任何操作。

void

start(QThread::Priority priority = InheritPriority)

通过调用run()开始执行线程。操作系统将根据优先级参数调度线程。如果线程已经在运行,则此函数不执行任何操作。

void

terminate()

终止线程的执行。根据操作系统的调度策略,线程可以立即终止,也可以不立即终止。在terminate()之后使用QThread::wait()来确保安全。

Signals

voidfinished()
voidstarted()

Static Public Members

QThread *

create(Function &&f, Args &&... args)

创建新的QThread 将执行函数的对象f 与参数

QThread *create(Function &&f)
QThread *currentThread()
Qt::HANDLEcurrentThreadId()
intidealThreadCount()
voidmsleep(unsigned long msecs)
void

sleep(unsigned long secs)

强制当前线程休眠秒。

voidusleep(unsigned long usecs)
void

yieldCurrentThread()

将当前线程的执行转换为另一个可运行线程(如果有)。请注意,操作系统决定切换到哪个线程。

Protected Functions

int

exec()

进入事件循环并等待直到exit(),返回传递给exit().返回的值为0,如果exit()通过调用exit().

virtual void

run()

线程的起点。在调用start()之后,新创建的线程调用此函数。默认实现只是调用exec()。
您可以重新实现此函数以促进高级线程管理。从此方法返回将结束线程的执行。

Static Protected Members

void

setTerminationEnabled(bool enabled = true)

属性启用或禁用当前线程的终止enabled 参数。线程必须由QThread.

什么时候enabled 为false,则禁用终止。未来呼叫QThread::terminate()将立即返回而不起作用。相反,终止被推迟,直到启用终止。

优先级:

  1. QThread::IdlePriority --> 最低的优先级
  2. QThread::LowestPriority
  3. QThread::LowPriority
  4. QThread::NormalPriority
  5. QThread::HighPriority
  6. QThread::HighestPriority
  7. QThread::TimeCriticalPriority
  8. QThread::InheritPriority --> 最高的优先级, 默认是这个

线程创建1

1.创建一个线程类的子对象,继承QThread

2.重写父类的run()方法,在该函数内部编写子线程要处理的具体业务流程

mythread.hpp

#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QObject>

class mythread : public QThread
{
    Q_OBJECT
public:
    explicit mythread(QObject *parent = nullptr);
protected:
    void run();
signals:
    void isDone();
};

#endif // MYTHREAD_H

mythread.cpp

#include "mythread.h"
#include <QDebug>
mythread::mythread(QObject *parent) : QThread(parent)
{

}
void mythread::run(){
    qDebug()<<"线程启动";
    QThread::sleep(5);
    emit isDone();
}

mywidget.h

#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QTimer>
#include <QWidget>
#include <mythread.h>
#include <QThread>
QT_BEGIN_NAMESPACE
namespace Ui { class myWidget; }
QT_END_NAMESPACE

class myWidget : public QWidget
{
    Q_OBJECT
private:
    mythread *thread;
    QTimer * timer;
public:
    myWidget(QWidget *parent = nullptr);
    ~myWidget();
    void dealTimeOut();
    void dealDone();
    void stopThread();
private slots:
    void on_pushButton_clicked();

private:
    Ui::myWidget *ui;
};
#endif // MYWIDGET_H

mywidget.cpp

#include "mywidget.h"
#include "ui_mywidget.h"
#include <QThread>
#include <QDebug>
myWidget::myWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::myWidget)
{
    timer =new QTimer(this);
    thread = new mythread(this);
//    定时器启动自动产生Timeout指令
    connect(timer,&QTimer::timeout,this,&myWidget::dealTimeOut);
    connect(thread,&mythread::isDone,this,&myWidget::dealDone);
    connect(this,&myWidget::destroyed,this,&myWidget::stopThread);
    ui->setupUi(this);
}
void myWidget::dealTimeOut(){
    static int i = 0;
    i++;
    ui->lcdNumber->display(i);
}
myWidget::~myWidget()
{
    delete ui;
}
void myWidget::stopThread(){
       thread->quit();
       thread->wait();
}

void myWidget::on_pushButton_clicked()
{
    if(timer->isActive()==false){
        timer->start(500);
         thread->start();
    }
//    QThread::sleep(5);

//    qDebug()<<"定时器结束";
}
void myWidget::dealDone(){
    qDebug()<<"it is over";
    timer->stop();

}

线程创建2

class Worker : public QObject //继承自QObject
{
    Q_OBJECT
 
public slots:
    void doWork(const QString &parameter) {
        QString result;
        /* ... here is the expensive or blocking operation ... */
        emit resultReady(result);
    }
 
signals:
    void resultReady(const QString &result);
};
 
class Controller : public QObject
{
    Q_OBJECT
    QThread workerThread;//创建一个线程
public:
    Controller() {
        Worker *worker = new Worker;//创建一个工作对象
        worker->moveToThread(&workerThread);//移动到线程种执行
        //当线程执行完成后,销毁work对象
        connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
        connect(this, &Controller::operate, worker, &Worker::doWork);
        connect(worker, &Worker::resultReady, this, &Controller::handleResults);
        workerThread.start();//开启线程
    }
    ~Controller() {
        workerThread.quit();//关闭线程
        workerThread.wait();//堵塞线程
    }
public slots:
    void handleResults(const QString &);
signals:
    void operate(const QString &);

线程创建3

创建

QRunnable是所有可执行对象的基类继承QRunnable类后重写其中的run()函数,即可实现线程开发。虽然基本步骤和QThread的做法一致。但是,QRunnable不能自己运行,而是必须借助于QThreadPool类运行

#ifndef THREAD02_H
#define THREAD02_H
 
#include <QRunnable>
 
class Thread02 : public QRunnable
{
public:
    Thread02();
    ~Thread02();
    void run() override;
};
 
#endif // THREAD02_H

#include "thread02.h"
#include <QThread>
 
#include <iostream>
 
using namespace std;
Thread02::Thread02()
{
    cout<< "Thread01 construct fun" << QThread::currentThread() << endl;
}
 
Thread02::~Thread02()
{
      cout<< "Thread01 destructor fun" << QThread::currentThread() << endl;
}
 
void Thread02::run()
{
     cout<< "Thread02 construct fun" << QThread::currentThread() << endl;
}

启动

线程的启动方法如下:

#include <QCoreApplication>

#include "thread02.h"
#include <iostream>
#include <QThreadPool>
using namespace std;
 
 
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
 
    cout<< "main thread" << QThread::currentThread() << endl;
 
   /* Thread01 th;
    th.start();*/
 
   Thread02 *th = new Thread02();
   QThreadPool::globalInstance()->start(th);
 
    cout<< "main thread end" << endl;
 
    return a.exec();
}

QThreadPool线程池

QThreadPool管理和回收单个QThread对象,以帮助减少使用线程的程序中的线程创建成本。每个Qt应用程序都有一个全局QThreadPool对象,可以通过调用globalInstance()来访问。

要使用其中一个QThreadPool线程,请子类化QRunnable并实现run()虚拟函数。然后创建该类的对象并将其传递给QThreadPool::start()。

class HelloWorldTask : public QRunnable
{
    void run() override
    {
        qDebug() << "Hello world from thread" << QThread::currentThread();
    }
};

HelloWorldTask *hello = new HelloWorldTask();
// QThreadPool takes ownership and deletes 'hello' automatically
QThreadPool::globalInstance()->start(hello);

Properties

  • activeThreadCount : const int   此属性表示线程池中的活动线程数
  • expiryTimeout : int 在expiryTimeout毫秒内未使用的线程被认为已过期并将退出。此类线程将根据需要重新启动。默认的expiryTimeout为30000毫秒(30秒)
  • maxThreadCount : int 此属性表示线程池使用的最大线程数。
  • stackSize : uint 此属性包含线程池工作线程的堆栈大小。

Public Functions公共职能

QThreadPool(QObject *parent = nullptr)
virtual~QThreadPool()
int

activeThreadCount() const

此属性表示线程池中的活动线程数

void

clear()

从队列中移除尚未启动的可运行对象。runnable->autoDelete()返回true的runnables被删除。

bool

contains(const QThread *thread) const

如果thread是由这个线程池管理的线程,则返回true

int

expiryTimeout() const

int

maxThreadCount() const

此属性表示线程池使用的最大线程数

void

releaseThread()

释放先前通过调用reserveThread()保留的线程。

void

reserveThread()

保留一个线程,忽略activeThreadCount()和maxThreadCount()。

voidsetExpiryTimeout(int expiryTimeout)
void

setMaxThreadCount(int maxThreadCount)

设置最大线程数量

void

setStackSize(uint stackSize)

uint

stackSize() const

此属性包含线程池工作线程的堆栈大小。

void

start(QRunnable *runnable, int priority = 0)

入一个运算到队列,注意start不一定立刻启动,只是插入到队列,排到了才会开始运行。需要传入QRunnable

void

start(std::function<void ()> functionToRun, int priority = 0)

bool

tryStart(QRunnable *runnable)

尝试启动一个

booltryStart(std::function<void ()> functionToRun)
bool

tryTake(QRunnable *runnable)

删除队列中的一个QRunnable,若当前QRunnable 未启动则返回成功

bool

waitForDone(int msecs = -1)

等待所有线程运行结束并退出,参数为等待时间-1表示一直等待到最后一个线程退出

mythread.h 

#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QRunnable>
#include <QObject>
#include <QDebug>
#include <QReadWriteLock>
#include <QTime>
#include <QSemaphore>
 
class mythread : public QObject, public QRunnable
{
        Q_OBJECT
public:
    mythread();
 
 
    //QThread的虚函数
    //线程处理函数
    //不能直接调用,通过start()间接调用
    void run();
 
signals:
    void isDone(int);   //处理完成信号
    void mySignal();    //注意!要使用信号,采用QObejct 和 QRunnable多继承,记得QObject要放在前面
 
public slots:
    //接收主线程的消息
    void recMegFromMain(QString);
};
 
class mythread1 : public QObject, public QRunnable
{
    Q_OBJECT
public:
 
    void run();
 
};
 
class mythread2  : public QObject, public QRunnable
{
    Q_OBJECT
public:
 
    void run();
};
 
 
class mythread3  : public QObject, public QRunnable
{
    Q_OBJECT
public:
 
    void run();
};
 
class mythread4  : public QObject, public QRunnable
{
    Q_OBJECT
public:
 
    void run();
};
#endif // MYTHREAD_H

mythread.cpp

#include "mythread.h"
#include <QMutex>
#include <QRandomGenerator>
#include <QWaitCondition>
#include <QThread>
/*
如果乱码就加上QStringLiteral();
#pragma execution_character_set("GB2312")
*/
mythread::mythread()
{
 
}
void mythread::run()
{
 
 
    for(int i=0;i<10;i++){
        //QThread::sleep(2);
        qDebug()<< QStringLiteral("PrintTask run 被调用,调用线程ID为:") << QThread::currentThread() << QStringLiteral( " 线程1打印数据:") <<QString::number(i);
    }
    //emit isDone(1);  //发送完成信号
}
void mythread::recMegFromMain(QString str)
{
    qDebug()<< "子线程接收到" <<str;
}
 
void mythread1::run()
{
 
    qDebug()<< QStringLiteral("PrintTask run 被调用,调用线程ID为:") << QThread::currentThread() ;
    for(int i=10;i<20;i++){
        QThread::sleep(2);
        qDebug()<< "线程2打印数据:" <<QString::number(i);
    }
    //emit isDone(1);  //发送完成信号
}
 
void mythread2::run()
{
 
    qDebug()<< "PrintTask run 被调用,调用线程ID为:" << QThread::currentThread() ;
    for(int i=20;i<30;i++){
        QThread::sleep(2);
        qDebug()<< "线程3打印数据:" <<QString::number(i);
    }
    //emit isDone(1);  //发送完成信号
}
 
void mythread3::run()
{
 
    qDebug()<< "PrintTask run 被调用,调用线程ID为:" << QThread::currentThread() ;
    for(int i=30;i<40;i++){
        QThread::sleep(2);
        qDebug()<< "线程4打印数据:" <<QString::number(i);
    }
    //emit isDone(1);  //发送完成信号
}
 
void mythread4::run()
{
 
    qDebug()<< "PrintTask run 被调用,调用线程ID为:" << QThread::currentThread() ;
    for(int i=40;i<50;i++){
        QThread::sleep(2);
        qDebug()<< "线程5打印数据:" <<QString::number(i);
    }
    //emit isDone(1);  //发送完成信号
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
 
#include <QMainWindow>
#include "mythread.h"
#include <QDebug>
#include <QMessageBox>
#include <QThreadPool>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
 
class MainWindow : public QMainWindow
{
    Q_OBJECT
 
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
 
    void dealDone();   //线程槽函数
 
    void mySlot();
 
    void receiveMsgFromThread(int);
 
    void sengMsgToThreadBtn();
private:
    Ui::MainWindow *ui;
 
    QThreadPool pool;
 
    mythread* task = new mythread();
    mythread1* task1 = new mythread1();
    mythread2* task2 = new mythread2();
    mythread3* task3 = new mythread3();
    mythread4* task4 = new mythread4();
signals:
    //给子线程发消息
    void sengMsgToThread(QString);
private slots:
    void on_pushButton_clicked();
    void on_pushButton_2_clicked();
    void on_pushButton_3_clicked();
    void on_pushButton_4_clicked();
    void on_pushButton_5_clicked();
    void on_pushButton_6_clicked();
    void on_pushButton_7_clicked();
    void on_pushButton_8_clicked();
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
 
#include <QReadWriteLock>
 
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
 
    //设置最大线程数为3的一个线程池
    pool.setMaxThreadCount(5);
 
}
 
MainWindow::~MainWindow()
{
    delete ui;
}
void MainWindow::sengMsgToThreadBtn()
{
    emit sengMsgToThread("hello");
}
// 定义槽函数 mySlot()
void MainWindow::mySlot()
{
    QMessageBox::about(this,"Tsignal", "响应线程中的mySlot函数");
}
//接收线程函数
void MainWindow::receiveMsgFromThread(int i)
{
    QString str = QString::number(i);
    qDebug()<<str;
}
void MainWindow::dealDone()
{
    ui->label->setText("线程停止");
    //停止线程
 
}
 
void MainWindow::on_pushButton_clicked()
{
 
    //QThread::sleep(1);
    //pool.waitForDone();           //等待任务结束
    on_pushButton_4_clicked();
    on_pushButton_5_clicked();
    on_pushButton_6_clicked();
    on_pushButton_7_clicked();
    on_pushButton_8_clicked();
 
    //启动线程,处理数据
    ui->label->setText("start");
 
}
 
void MainWindow::on_pushButton_2_clicked()
{
    //pool.releaseThread();
    //停止线程
    //dealDone();
    //sengMsgToThreadBtn();
}
 
void MainWindow::on_pushButton_3_clicked()
{
    qDebug() <<pool.activeThreadCount();
    //sengMsgToThreadBtn();
}
 
void MainWindow::on_pushButton_4_clicked()
{
    pool.start(task);             //任务放进线程池
    task->setAutoDelete(false);
}
 
void MainWindow::on_pushButton_5_clicked()
{
    pool.start(task);             //任务放进线程池
    task->setAutoDelete(false);
    /*
    pool.start(task1);
    task1->setAutoDelete(false);
    */
}
 
void MainWindow::on_pushButton_6_clicked()
{
    pool.start(task);             //任务放进线程池
 
    //pool.start(task2);
}
 
void MainWindow::on_pushButton_7_clicked()
{
    pool.start(task);             //任务放进线程池
    //pool.start(task3);
}
 
void MainWindow::on_pushButton_8_clicked()
{
    pool.start(task);             //任务放进线程池
    //pool.start(task4);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值