【QT】Qt文件和多线程

news/2024/12/13 17:14:11/

在这里插入图片描述
个人主页~


Qt系统内容

  • 一、Qt文件
    • 1、文件读写
    • 2、文件和目录信息
  • 二、多线程
    • 1、线程使用
      • timethread.h
      • widget.h
      • timethread.cpp
      • widget.cpp
    • 2、线程安全
      • (1)互斥锁
        • QMutex
        • QMutexLocker
        • 一个例子
          • mythread.h
          • mythread.cpp
          • widget.cpp
        • QReadWriteLocker、QReadLocker、QWriteLocker
      • (2)条件变量
      • (3)信号量

一、Qt文件

对于Qt文件QFile的相关关系都在下面这个思维导图里面了,它的父类是QFileDevice,爷爷类是QIODevice,Qt中所有的输入输出的类都是继承自QIODevice,其中也包括网络IO、串口IO、蓝牙IO等

在这里插入图片描述

1、文件读写

对于文件的操作主要有读数据、写数据、关闭文件

操作说明
QIODevice::NotOpen没有打开设备
QIODevice::ReadOnly以只读方式打开设备
QIODevice::WriteOnly以只写方式打开设备
QIODevice::ReadWrite以读写方式打开设备
QIODevice::Append以追加方式打开设备,数据将写到文件末尾
QIODevice::Truncate每次打开文件后重写文件内容,原内容将被删除
QIODevice::Text在读⽂件时,行尾终止符会被转换为’\n’,当写入⽂件时,行尾终止符会被转换为本地编码,如Win32上为’\r\n’;
QIODevice::Unbuffered无缓冲形式打开文件,绕过设备中的任何缓冲区
QIODevice::NewOnly文件存在则打开失败,不存在则创建文件

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);connect(ui->pushButton,&QPushButton::clicked,[=](){//获得文件路径QString path = QFileDialog::getOpenFileName(this,"打开文件","C:\\Users\\14725\\Desktop");//将路径设置为lineEdit的内容ui->lineEdit->setText(path);//通过path路径打开文件QFile file(path);//以只读方式打开文件file.open(QIODevice::ReadOnly);//读取所有的内容存在str字符串中QString str = file.readAll();//将字符串放到textEdit中ui->textEdit->setText(str);file.close();});
}

qfile

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);connect(ui->pushButton,&QPushButton::clicked,[=](){QString path = QFileDialog::getOpenFileName(this,"打开文件","C:\\Users\\14725\\Desktop");ui->lineEdit->setText(path);QFile file(path);//以写方式打开文件file.open(QIODevice::Append);//写入的内容file.write("写进去的字");file.close();});
}

qfile_2

2、文件和目录信息

方法说明
isDir检查是否是目录
isExecutable检查是否是可执行文件
fileName获得文件名
completeBaseName获取完整的文件名
suffix获取文件后缀
completeSuffix获取完整文件后缀
size获取文件大小
isFile判断是否为文件
fileTime获取文件的创建时间、修改时间、最近访问时间等
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QString path = QFileDialog::getOpenFileName(this,"打开文件","C:\\Users\\14725\\Desktop");QFileInfo fileinfo(path);//这里的.toUtf8().data()后缀主要为为了将字符串转化为C字符串,不加时输出为:"阿门.txt"//加上输出为:阿门.txt,会去掉引号qDebug() << "文件名:" << fileinfo.fileName().toUtf8().data();qDebug() << "后缀名:" << fileinfo.suffix().toUtf8().data();qDebug() << "文件大小:" << fileinfo.size();qDebug() << "文件路径:" << fileinfo.path().toUtf8().data();qDebug() << "是否为文件:" << fileinfo.isFile();qDebug() << "是否为目录:" << fileinfo.isDir();QDateTime time1 = fileinfo.fileTime(QFileDevice::FileBirthTime);qDebug() << "创建时间:" << time1.toString("yyyy-MM-dd hh:mm:ss").toUtf8().data();QDateTime time2 = fileinfo.lastModified();qDebug() << "上次修改时间:" << time2.toString("yyyy-MM-dd hh:mm:ss").toUtf8().data();
}

文件属性
在这里插入图片描述
程序输出
在这里插入图片描述

二、多线程

1、线程使用

在Qt中多线程的处理一般是通过QTread类来控制实现的,这部分的内容与Linux内容强相关,我在学习这一块的时候是没有学习过Linux的,所以我是通过0Linux的基础来写下这部分内容的

API说明
run线程入口函数
start通过调用run开始执行线程,操作系统根据优先级判定,如果线程正在运行,则这个函数相当于没有
currentTread返回一个指向管理当前执行线程的QTread指针
isRunning判断线程是否正在运行
sleep使程序休眠,单位为s,类似的函数:msleep单位为ms,usleep单位为us
wait阻塞线程,与此QTread对象关联的线程已经完成执行或者尚未启动都返回true,如果等待超时,返回false
terminate终止线程执行,通过操作系统的调度决定是否立即终止
finished线程结束后发出该信号

创建一个自定义类timethread,继承自QThread,在ui上创建一个pushbutton和label

timethread.h

class TimeThread : public QThread
{Q_OBJECT;
public:TimeThread();//线程任务函数void run();
signals://声明信号函数void sendTime(QString Time);
};

widget.h

class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();
private slots:void showTime(QString Time);void on_pushButton_clicked();private:Ui::Widget *ui;//定义线程对象TimeThread t;
};

timethread.cpp

void TimeThread::run()
{while (1) {QString time = QTime::currentTime().toString("hh::mm::ss");//发送信号emit sendTime(time);sleep(1);//每一秒发送一次信号}
}

widget.cpp

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//当t每次sendTime的时候,触发showTimeconnect(&t,&TimeThread::sendTime,this,&Widget::showTime);
}Widget::~Widget()
{delete ui;
}void Widget::showTime(QString Time)
{//设置label的内容为时间ui->label->setText(Time);
}void Widget::on_pushButton_clicked()
{//开启线程t.start();
}

QTread

我们前面也说过,线程函数内部不允许操作ui图形界面,一般是用作数据处理的
connect函数有五个参数,第五个参数就是只有在多线程的时候才有意义,用于指定信号和槽的连接类型,同时影响信号的传递方式和槽函数的执行顺序

参数说明
Qt::AutoConnection根据信号和槽函数所在的线程自动选择连接类型,同一线程使用Qt::DirectConnection,不同线程使用Qt::UniqueConnection
Qt::DirectConnection信号发出时,槽函数会立即在同一线程中执行,适用于信号和槽在同一线程时
Qt::QueuedConnection信号发出时,槽函数会被插入到接收对象所属的线程的事件队列中,等待下一次时间循环时执行,适用于信号和槽不在同一线程
Qt::BlockingQueuedConnection信号发出时,发送信号的线程会被阻塞,直到槽函数执行完毕,适用于信号和槽不在同一线程
Qt::UniqueConnection确保信号与槽之间唯一连接关系的标志,可以使用位或操作与上述四种一种连接类型组合使用,可以避免重复连接

2、线程安全

(1)互斥锁

互斥锁是一种保护和防止多个线程同时访问同一对象实例的办法,主要通过QMutex类来处理

QMutex

用于保护共享资源的访问,实现线程间的互斥操作,在多线程的环境下,通过互斥锁来控制对共享数据的访问,确保线程安全

QMutex mutex;
mutex.lock();//上锁//访问共享资源mutex.unlock();//解锁
QMutexLocker

可以简化对互斥锁的上锁解锁操作,避免忘记解锁导致死锁

QMutex mutex;
{QMutexLocker locker(&mutex);//作用域内自动上锁//访问共享资源...}//作用域结束自动解锁
一个例子
mythread.h
class MyThread : public QThread
{
public:MyThread(QObject* parent = nullptr);void run();private://定义全局变量static QMutex mutex;static int num;
};
mythread.cpp
void MyThread::run()
{while (1) {this->mutex.lock();//锁上//每有一个线程进来就打印线程以及递增的数字qDebug() << this <<" : " << this->num++;this->mutex.unlock();//解锁QThread::sleep(1);}
}

在这个代码块中,mutex.lock() 和 mutex.unlock() 手动管理互斥锁,每次打印完信息后立即释放锁,然后进行 QThread::sleep(1),由于锁已经释放,其他线程可以立即进入这段代码,导致线程的执行和打印信息可能是无序的

void MyThread::run()
{while (1) {QMutexLocker locker(&mutex);qDebug() << this <<" : " << this->num++;QThread::sleep(1);}
}

在这个代码块中,使用了 QMutexLocker 来管理锁,QMutexLocker 会在它的作用范围内自动锁定 mutex,并在 locker 离开作用域时(即循环的下一次迭代开始时)自动解锁,在这里,QThread::sleep(1) 位于锁的作用范围内,所以整个 sleep 期间锁不会释放,这样可以保证一次只有一个线程在运行这段代码,从而避免线程间的竞争

widget.cpp
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);MyThread* t1 = new MyThread(this);MyThread* t2 = new MyThread(this);t1->start();t2->start();
}
QReadWriteLocker、QReadLocker、QWriteLocker

QReadWriteLocker:读写锁类,用于控制读和写的并发访问
QReadLocker:读操作上锁,允许多个线程同时读取共享资源
QWriteLocker:写操作上锁,只允许一个线程写入共享资源

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

(2)条件变量

因为在多线程编程中,某些线程需要等待某些条件满足才能执行,此时线程会使用锁的机制来阻塞其他线程,当条件满足时,等待条件的线程将被另一个线程唤醒

QWaitCondition是Qt框架提供的条件变量类,用于线程之间的通信和同步,在某个条件满足时等待或唤醒线程,用于线程的同步和协调

QMutex mutex;
QWaitCondition condition;//等待线程中
mutex.lock();//检查条件是否满足,不满足就等待
while (!conditionFullfilled()) 
{condition.wait(&mutex);//条件满足释放锁
}mutex.unlock();//------------------------------------------------------------------------------------//在改变条件的线程中
mutex.lock();
//改变条件
changeCondition();
condition.wakeAll(); //唤醒等待的线程mutex.unlock();

(3)信号量

QSemaphone是Qt框架提供的计数信号类,用于控制同时访问共享资源的线程数量,用于限制并发线程数量,用于解决一些资源有限的问题

QSemaphore semaphore(2); //同时允许两个线程访问共享资源//在需要访问共享资源的线程中
semaphore.acquire(); //尝试获取信号量,若已满则阻塞//访问共享资源
//...
semaphore.release(); //释放信号量
//在另⼀个线程中也要进行类似操作

今日分享就到这了~

在这里插入图片描述


http://www.ppmy.cn/news/1545084.html

相关文章

gerrit 搭建遇到的问题

1、启动Apache&#xff0c;端口被占用 : AH00072: make sock: could not bind to address (0S 10048)通常每个套接字地址(协议/网络地址/端口)只允许使用一次。: AH00072: make sock: could not bind to address 0.0.0.:443 a AH00451: no listening sockets available, shutti…

Docker篇(容器的备份与迁移)

目录 一、容器保存为镜像 二、镜像备份 三、镜像恢复与迁移 一、容器保存为镜像 docker commit mynginx mynginx_i 目的&#xff1a;主要的作用就是配置好的一些容器&#xff0c;可以得到复用&#xff0c;就不需要重新再次配置了 二、镜像备份 注意是保存在当前执行命令的…

《Linux运维总结:基于银河麒麟V10+ARM64架构CPU部署redis 6.2.14 TLS/SSL哨兵集群》

总结:整理不易,如果对你有帮助,可否点赞关注一下? 更多详细内容请参考:《Linux运维篇:Linux系统运维指南》 一、简介 Redis 哨兵模式是一种高可用性解决方案,它通过监控 Redis 主从架构,自动执行故障转移,从而确保服务的连续性。哨兵模式的核心组件包括哨兵(Sentine…

在 C# 中,如何实现观察者模式?

观察者模式是一种设计模式&#xff0c;它定义了一种一对多的依赖关系&#xff0c;让多个观察者对象同时监听某一个主题对象。当该主题对象的状态发生变化时&#xff0c;会通知所有观察者对象&#xff0c;使它们能够自动更新自己。这个模式常用于事件处理系统、通知系统等场景。…

思维导图工具有哪些?10款思维导图特色介绍

电脑的普及&#xff0c;互联网的便捷。使我们平时工作、学习等场景下&#xff0c;常常离不开思维导图的辅助。思维导图是可以让我们所需要介绍的知识点以图文形式结合&#xff0c;展示出来。帮助我们方便理解。因此&#xff0c;一款好的思维导图工具&#xff0c;能让我们制作的…

Jdbc批处理功能和MybatisPlus

文章目录 1. 序言2. JDBC批处理功能和rewriteBatchedStatements3. JDBC批量插入的测试4. MybatisPlus#ServiceImpl.saveBatch()5. 结语&#xff1a;如果对大家有帮助&#xff0c;请点赞支持。如果有问题随时在评论中指出&#xff0c;感谢。 1. 序言 MybatisPlus的ServiceImpl类…

大模型微调:Adapter;在大模型基础上增加低秩矩阵或者adapter有什么用,这样还增加运算

目录 大模型微调:Adapter 一、Adapter的具体实现方式 二、为何能在大模型基础上实现特定功能 三、举例说明 在大模型基础上增加低秩矩阵或者adapter有什么用,这样还增加运算 增加低秩矩阵的用途和优势 增加Adapter的用途和优势 关于运算复杂性的考虑 大模型微调:Ada…

软件对象粒度控制与设计模式在其中作用的例子

在软件设计中&#xff0c;确定对象的粒度&#xff08;Granularity&#xff09;是一个重要的考量因素&#xff0c;它决定了对象的职责范围和复杂程度。粒度过细或过粗都可能影响系统的可维护性和性能。设计模式可以帮助我们在不同层面控制粒度和管理对象之间的交互。以下是对每种…