07 线程学习

2023-10-15 18:35:09 浏览数 (1)

一 qt线程角色

子线程完成与UI线程无关的工作,并且能够保持与UI线程通信

二 qt中线程

在QT中,对于 线程操作也是提供类(QThread)来进行封装,然后再学习该类的API接口

参数

用途

Header:

#include

qmake:

QT = core

Inherits:

QObject //继承于QObject

从官方文档可以看出,如果一个线程类要支持信号和槽,那么,该类要直接或者间接的继承于QObject类,并且在类中要声明宏:Q_OBJECT

2.1 线程的创建

线程的创建方式:自定义一个类继承于QThread,并且 重写该类的run函数,run函数中,就是 子线程要执行任务。在创建线程后,要进行启动线程 操作

代码语言:javascript复制
class WorkerThread : public QThread
{
      
      void run() override { //该函数是一个普通成员函数,执行后就结束退出
                           //如果想要子线程一直执行,则要使用while
          //子线程要的执行任务
      }
 
};
代码语言:javascript复制
  WorkerThread *workerThread = new WorkerThread(this);
  workerThread->start();//子线程一定要调用start启动,否则,不会执行

线程的几点注意事项:

  1. 默认情况下,void run() 只执行一次,想要执行多次,要手动使用循环语句
  2. 子线程一定要调用start启动,否则,不会执行
  3. 对于信号和槽,在子线程中,不是必须使用,除非,要使用信号和槽来跟其他线程通信
代码语言:javascript复制
 线程实现的步骤:
第一步:创建一个子类继承于QThread,并且重写run函数
第二步:创建子线程对象
第三步:启动子线程 ---- start()
2.2 线程类的基本接口和使用

启动 和终止线程

参数

用途

void

quit() //退出一个线程循环,可以起作 停止线程

void

start(QThread::Priority priority = InheritPriority)//启动线程

void

terminate()//终止线程

静态成员函数接口:

参数

用途

void

msleep(unsigned long msecs)//毫秒级

void

sleep(unsigned long secs)//秒级

void

usleep(unsigned long usecs)//微秒

参数

用途

QThread *

currentThread() //获取当前的线程

Qt::HANDLE

currentThreadId()//返回的ID值给是QT内部使用,应用程序不能使用

来自于QObject类中的成员函数:设置和获取线程的名字

参数

用途

void

setObjectName(const QString &name)

QString

objectName() const

基本案例:利用子线程来实现计数,并将计数的结果更新到UI 第一步:创建子线程类

代码语言:javascript复制
//发一条通知给UI线程(UI控件)
class MyThread : public QThread
{
   Q_OBJECT  //在该类中,可以支持信号和槽,另外,该类还要间接或者直接继承于QObject
public:
    explicit MyThread(QObject *parent = nullptr){}
    ~MyThread(){}

    void run() override
    {
       static int i = 0;
        while (1) {

            QThread::sleep(1);
            emit sendMsg(QString::number(i  ));

        }
    }
signals:
    void sendMsg(const QString&msg);
};

第二步:在UI线程中,创建子线程并启动子线程

代码语言:javascript复制
 thread = new MyThread(this)
 //建立子线程与UI线程(MainWindow)的信号和槽连接
connect(thread,&MyThread::sendMsg,this,&MainWindow::recvMsg);
    thread->start();//启动线程

第四步:在UI线程的槽函数中,更新UI控件

代码语言:javascript复制
void MainWindow::recvMsg(const QString &msg)
{
      ui->label->setText(msg);
}

第五步:终止子线程

代码语言:javascript复制
void MainWindow::on_stopButton_clicked()
{
    thread->terminate(); //终止线程
}

三 线程同步

线程同步方式

  1. 互斥锁
  2. 读写锁
  3. 信号量

线程同步:多个线程之间在处理数据时,按照一 定次序来进行完成,比如:

  • 数据接收 — 数据处理 — 数据发送,把这个过程称之为线程同步

在QT线程 编程中,也提供线程同步机制QMutex

  • QMutexLocker
  • QReadWriteLock
  • QSemaphore
  • QWaitCondition

同步机制的目的是为了保护数据或者代码段,在多线程中,每次只允许一个线程来进行访问 在线程同步中,把要保护的数据或者代码段的上下文叫作临界区 临界区中所包含的资源就是临界资源,比如:变量 寄存器

代码语言:javascript复制
static int number = 0;
static QMutex mutex;


class Work1Thread:public QThread
{
public:
    explicit Work1Thread(QWidget *parent = nullptr){}
    ~Work1Thread(){}
    void run()override
    {
        while (1) {

            mutex.lock();
            QThread::sleep(2);
            qDebug() << "Work1Thread"<<number  ;
            mutex.unlock();
        }
    }

};

class Work2Thread:public QThread
{
public:
    explicit Work2Thread(QWidget *parent = nullptr){}
    ~Work2Thread(){}
    void run()override
    {
        while (1) {
          mutex.lock();
            QThread::sleep(1);
            
            qDebug() << "Work2Thread"<<number  ;
            mutex.unlock();
        }
    }

};

0 人点赞