QT第五课------QT系统相关------线程

作者前言

🎂 ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂

​🎂 作者介绍: 🎂🎂

🎂 🎉🎉🎉🎉🎉🎉🎉 🎂

🎂作者id:老秦包你会, 🎂

简单介绍:🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂

喜欢学习C语言、C++和python等编程语言,是一位爱分享的博主,有兴趣的小可爱可以来互讨 🎂🎂🎂🎂🎂🎂🎂🎂

🎂个人主页::小小页面🎂

🎂gitee页面:秦大大🎂

🎂🎂🎂🎂🎂🎂🎂🎂

🎂 一个爱分享的小博主 欢迎小可爱们前来借鉴🎂


线程

介绍

在Linux中有多线程的api,在qt中也有对应的多线程api,但是这个api是对系统的api进行封装的,在C++11中,就引入了std::thread,如果需要进行比较 也就是(Linux的api<std::thread<Qt的api)。Qt的多线程的api是参考了java的api设计方式

QThread

需要创建对应的对象,在创建对象的时候,需要重点指定入口函数,也就是使用QThread创建对象的时候,需要对run函数进行重写

API

下面是Qthread提供的一些常用的api:

前面我们使用了定时器来实现一个时间显示器, 我们这次使用这个线程来实现时间显示器

复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);


    layou = new QVBoxLayout(this->centralWidget());
     //创建显示器
    QLCDNumber* nb = new QLCDNumber();
    nb->resize(100,200);

    //创建开始按钮
    QPushButton* button = new QPushButton();
    button->resize(300,400);
    button->setText("开始");

    layou->addWidget(nb,1);
    layou->addWidget(button,1);

    //获取中心窗口
    this->centralWidget()->setLayout(layout());
    thread = new threead();
    connect(button,&QPushButton::clicked,this,[=]()
    {
        thread->start();
    });
    connect(thread,&threead::currenTime,this,[=](const QString &time)
    {
        nb->display(time);
    });
}



/********thread。cpp******/
threead::threead()
    :QThread()
{

}

void threead::run()
{
    //写一个死循环
    while (1)
    {
        QTime* time = new QTime();
        emit currenTime(time->currentTime().toString("y=M=d-H:m"));
        sleep(1);
    }

}

效果图:

注意:

statu函数执行的时候,就是创建线程的过程,这个过程就会调用到run函数,无需我们调用,

还有就是,创建的线程无法直接更改主线程的界面的内容, 只能通过主线程进行修改

线程安全

线程安全是指在多线程环境中,多个线程并发访问共享资源时,不会导致数据不一致或错误的状态。一般的情况就是增加一个锁,以防数据被同时进行修改。

互斥锁(Mutex)

特点:QMutex 是 Qt 框架提供的互斥锁类,⽤于保护共享资源的访问,实现线程间的互斥操作。

⽤途:在多线程环境下,通过互斥锁来控制对共享数据的访问,确保线程安全。

下面写一个多进程访问一个变量进行更改的代码

锁的写法:

复制代码
QMutex mutex;
mutex.lock(); //上锁
//访问共享资源
//...
mutex.unlock(); //解锁

/*****addnum。cpp***/
void addnum::run()
{
    while(1)
    {
        mutex->lock();
        qDebug()<< "当前的值为"<< num;
        qDebug()<< "当前的进程为"<<this->currentThreadId();
        num++;
        mutex->unlock();
        sleep(1);
    }
}

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    addnum * thread_One = new addnum();
    addnum * thread_Two = new addnum();
    thread_One->start();
    thread_Two->start();
//    thread_One->wait();
//    thread_Two->wait();
    qDebug()<<addnum::num;
}

​上面的代码有两种运行结果, 一个是直接输出主线程的,然后再输出其他线程的(有注释掉wait函数),另一种是输出其他线程的,最后再输出主线程的,

图一:

图二:

可以看清楚,原因是这个代码中的线程有三个, 分别是主线程和thread_Two 以thread_One,这三个线程是并发的,输出的结果就会有错, 还有另一个方面就是没有添加锁的情况, 例如thread_Two 和thread_One在运行的时候,thread_Two 刚好把num从而2变成3,而与此同时thread_One拿到的num的值刚好是2.也刚好完成变成3的过程,这里就会有线程安全问题

QMutexLocker

简化对互斥锁的上锁和解锁操作,避免忘记解锁导致的死锁等问题。简单的说。就是前面写的代码有时候会忘记解锁,就会造成线程阻塞,进行导致进程瘫痪,这个类可以进一步的解决这个问题

写法:

复制代码
QMutex mutex;
{
 QMutexLocker locker(&mutex); //在作⽤域内⾃动上锁
 
 //访问共享资源
 }//在作⽤域结束时⾃动解锁

所以我们可以更改代码为

复制代码
void addnum::run()
{
    while(1)
    {
//        mutex->lock();
        QMutexLocker locker(mutex);
        qDebug()<< "当前的值为"<< num;
        qDebug()<< "当前的进程为"<<this->currentThreadId();
        num++;
//        mutex->unlock();
        sleep(1);
    }
}

这个QMutexLocker这个写法, 不一定需要多写{}这个,也可以在一些场合上进行套用

除了有这个锁之外,还有一些其他的锁

QReadWriteLocker、QReadLocker、QWriteLocker

QReadWriteLock 是读写锁类,⽤于控制读和写的并发访问。

QReadLocker ⽤于读操作上锁,允许多个线程同时读取共享资源。

QWriteLocker ⽤于写操作上锁,只允许⼀个线程写⼊共享资源。

⽤途:在某些情况下,多个线程可以同时读取共享数据,但只有⼀个线程能够进⾏写操作。读写锁提供了更⾼效的并发访问⽅式。

写法:

复制代码
QReadWriteLock rwLock;
//在读操作中使⽤读锁
{
 QReadLocker locker(&rwLock); //在作⽤域内⾃动上读锁
 
 //读取共享资源
 //...
 
} //在作⽤域结束时⾃动解读锁


//在写操作中使⽤写锁
{
 QWriteLocker locker(&rwLock); //在作⽤域内⾃动上写锁
 
 //修改共享资源
 //...
 
} //在作⽤域结束时⾃动解写锁

条件变量

在多线程编程中,假设除了等待操作系统正在执⾏的线程之外,某个线程还必须等待某些条件满⾜才能执⾏,这时就会出现问题。这种情况下,线程会很⾃然地使⽤锁的机制来阻塞其他线程,因为这只是线程的轮流使⽤,并且该线程等待某些特定条件,⼈们会认为需要等待条件的线程,在释放互斥锁或读写锁之后进⼊了睡眠状态,这样其他线程就可以继续运⾏。当条件满⾜时,等待条件的线程将被另⼀个线程唤醒。

简单的说就是条件变量通常与互斥锁(mutex)结合使用。当一个线程需要等待某个条件时,它会释放互斥锁并进入等待状态,直到另一个线程通知它条件已满足。

条件变量主要有以下几种操作:

等待(wait):线程在条件变量上等待,同时释放与条件变量相关联的互斥锁。

通知(notify):当条件满足时,线程可以通知一个或多个在条件变量上等待的线程,使它们恢复执行。

通知所有(notifyAll):通知所有在条件变量上等待的线程。

相关推荐
leo__5201 天前
基于菲涅耳衍射积分的空心高斯光束传输数值模拟(MATLAB实现)
开发语言·matlab
昵称已被吞噬~‘(*@﹏@*)’~1 天前
【RL+空战】学习记录03:基于JSBSim构造简易空空导弹模型,并结合python接口调用测试
开发语言·人工智能·python·学习·深度强化学习·jsbsim·空战
短剑重铸之日1 天前
《SpringBoot4.0初识》第一篇:前瞻与思想
java·开发语言·后端·spring·springboot4.0
2501_941877981 天前
从配置热更新到运行时自适应的互联网工程语法演进与多语言实践随笔分享
开发语言·前端·python
Wyn_1 天前
【ZMQ/QT】Windows11 + Qt 安装配置zmq(亲测可用)
qt·zmq·windows11
lsx2024061 天前
Python 运算符详解
开发语言
程序炼丹师1 天前
CMakeLists中 get_filename_component详解
开发语言
꧁Q༒ོγ꧂1 天前
C++ 入门完全指南(四)--函数与模块化编程
开发语言·c++
864记忆1 天前
Qt创建连接注意事项
数据库·qt·nginx
listhi5201 天前
对LeNet-5的matlab实现,识别MINST手写数字集
开发语言·matlab