线程
①、就绪状态 :
线程一旦被new Thread 创建之后,就会立刻进入(RUnnable)就绪状态,因为CPU资源十分宝贵,所以需要等待CPU资源。
②、运行状态:
当该线程枪战到CPU资源后,就会立刻进入执行状态
③、阻塞状态
如果遇到sleep()或者IO阻塞,则会进入阻塞状态,当sleep()时间到了或者IO阻塞返回获得同步锁,则再次进入就绪状态
sleep():使得线程在指定的时间内进入阻塞状态,不能得到CPU资源,且不会释放锁资源,时间一过,就会立刻进入就绪状态
wait():使得线程进入阻塞状态,释放所资源,和notify()搭配使用
④、死亡状态:
(1)、run()方法正常退出,线程自然死亡
(2)、一个未捕获的异常,终止了线程,使得线程异常死亡
线程池
1.1、线程池(QThreadPool)管理并重新设置单个QThread对象的样式,以帮助减少使用线程的程序中的线程创建成本。每个Qt应用程序都有一个全局QThreadPool对象,可以通过调用globalInstance()来访问该对象。
1.2、要使用QThreadPool线程之一,请将QRunnable子类化并实现run()虚拟函数。然后创建该类的对象并将其传递给QThreadPool::start()。
1.3、默认情况下,QThreadPool会自动删除QRunnable。使用qrunable::setAutoDelete()更改自动删除标志。
1.4、线程池可以维护线程数据,如果需要多线程执行任务时,只要将任务的指令传递给线程池即可,线程池会根据可用线程进行安排。
1.5、线程池可以防止线程之间资源竞争
多线程
2.1、多线程的创建及销毁,需要频繁的系统交互,会产生很大开销,若频繁的创建线程,建议使用线程池。
.cpp文件
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
myThreadPool * Tp = new myThreadPool(this);
QThreadPool::globalInstance()->start(Tp);
connect(Tp,&myThreadPool::setNum,this,MainWindow::getNum);//建立信号槽函数
}
MainWindow::~MainWindow()
{
delete ui;
delete Tp;
}
void MainWindow :: getNum(int i)
{
ui->label->setText(QString::number(i));//将数字显示在对话框组件中
}
头文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QThreadPool>
#include <QRunnable>
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class myThreadPool :public QObject,public QRunnable//自定义类,公有继承 QObject类和 QRunnable类,【且顺序不能颠倒】
{
Q_OBJECT
public:
explicit myThreadPool(QWidget *parent = nullptr){}
~myThreadPool(){}
private:
int i;
virtual void run()//在run()函数中实现用户自定义功能
{
while (1)
{
QThread::sleep(1);//间隔一秒
emit setNum(i);//发送数字信号函数
i++;
}
}
signals:
void setNum(int i);//定义一个发送数字信号函数
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void getNum(int i);//定义一个接收数字槽函数
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
线程调用UI组件
一、通过调用线程来实现
class myThreadPhoto : public QThread //自定义一个类,共有继承QThread
{
Q_OBJECT
public:
explicit myThreadPhoto(QWidget *parent = nullptr){}
~myThreadPhoto(){}
//重写虚函数
virtual void run() //在run函数中执行用户自定义操作
{
while (1)
{
emit sentPicUpdate(); //每间隔一秒就会发送一个更新图片【自定义信号】信号
QThread :: sleep(1);
}
}
signals:
void sentPicUpdate(); //建立一个信号,通过发送该信号,建立信号和槽函数,来实现线程调用UI组件
};
class MainWindow : public QMainWindow //MainWindow类
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_actionstart_triggered();
void updatePhoto(); //在MainWindow中创建一个槽函数,用来实现UI组件的调用
void on_actionstop_triggered();
private:
Ui::MainWindow *ui;
myThreadPhoto *ph;
int dex;
};
二、通过线程池来实现调用UI组件
注意:在线程池调用UI组件时,必须要继承QObject,则必须要使用Q_OBJECT
class myThreadPool :public QObject,public QRunnable //myThreadPool继承 QObject类和QRunnable类【顺序不能改变】
{
Q_OBJECT
public:
explicit myThreadPool(QWidget *parent = nullptr){}
~myThreadPool(){}
private:
int i;
virtual void run() //在run函数中实现发送数据
{
while(1)
{
emit setNum(i);
QThread::sleep(1); //每间隔1秒发送一次数据
i++;
}
}
signals:
void setNum(int i); //在线程池自定义一个信号
};
class MainWindow : public QMainWindow //在MainWindow 中构建一个槽函数
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void getNum(int i); //接收数据槽函数,实现对UI组件的修改,调用
private:
Ui::MainWindow *ui;
};
myThreadPool * Tp = new myThreadPool; //在.cpp文件中,创建一个任务
QThreadPool::globalInstance()->start(Tp); //线程池接收任务,开启线程池
connect(Tp,&myThreadPool::setNum,this,&MainWindow::getNum);//建立信号和槽函数 setNum:在线程池中定义的信号 getNum:在MainWindow 中构建的槽函数