深圳 汽車網(wǎng)站建設百度網(wǎng)站首頁提交入口
個人主頁~
Qt系統(tǒng)內容
- 一、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,其中也包括網(wǎng)絡IO、串口IO、藍牙IO等
1、文件讀寫
對于文件的操作主要有讀數(shù)據(jù)、寫數(shù)據(jù)、關閉文件
操作 | 說明 |
---|---|
QIODevice::NotOpen | 沒有打開設備 |
QIODevice::ReadOnly | 以只讀方式打開設備 |
QIODevice::WriteOnly | 以只寫方式打開設備 |
QIODevice::ReadWrite | 以讀寫方式打開設備 |
QIODevice::Append | 以追加方式打開設備,數(shù)據(jù)將寫到文件末尾 |
QIODevice::Truncate | 每次打開文件后重寫文件內容,原內容將被刪除 |
QIODevice::Text | 在讀?件時,行尾終止符會被轉換為’\n’,當寫入?件時,行尾終止符會被轉換為本地編碼,如Win32上為’\r\n’; |
QIODevice::Unbuffered | 無緩沖形式打開文件,繞過設備中的任何緩沖區(qū) |
QIODevice::NewOnly | 文件存在則打開失敗,不存在則創(chuàng)建文件 |
讀
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 | 檢查是否是可執(zhí)行文件 |
fileName | 獲得文件名 |
completeBaseName | 獲取完整的文件名 |
suffix | 獲取文件后綴 |
completeSuffix | 獲取完整文件后綴 |
size | 獲取文件大小 |
isFile | 判斷是否為文件 |
fileTime | 獲取文件的創(chuàng)建時間、修改時間、最近訪問時間等 |
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() << "創(chuàng)建時間:" << 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類來控制實現(xiàn)的,這部分的內容與Linux內容強相關,我在學習這一塊的時候是沒有學習過Linux的,所以我是通過0Linux的基礎來寫下這部分內容的
API | 說明 |
---|---|
run | 線程入口函數(shù) |
start | 通過調用run開始執(zhí)行線程,操作系統(tǒng)根據(jù)優(yōu)先級判定,如果線程正在運行,則這個函數(shù)相當于沒有 |
currentTread | 返回一個指向管理當前執(zhí)行線程的QTread指針 |
isRunning | 判斷線程是否正在運行 |
sleep | 使程序休眠,單位為s,類似的函數(shù):msleep單位為ms,usleep單位為us |
wait | 阻塞線程,與此QTread對象關聯(lián)的線程已經(jīng)完成執(zhí)行或者尚未啟動都返回true,如果等待超時,返回false |
terminate | 終止線程執(zhí)行,通過操作系統(tǒng)的調度決定是否立即終止 |
finished | 線程結束后發(fā)出該信號 |
創(chuàng)建一個自定義類timethread,繼承自QThread,在ui上創(chuàng)建一個pushbutton和label
timethread.h
class TimeThread : public QThread
{Q_OBJECT;
public:TimeThread();//線程任務函數(shù)void run();
signals://聲明信號函數(shù)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");//發(fā)送信號emit sendTime(time);sleep(1);//每一秒發(fā)送一次信號}
}
widget.cpp
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//當t每次sendTime的時候,觸發(fā)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
我們前面也說過,線程函數(shù)內部不允許操作ui圖形界面,一般是用作數(shù)據(jù)處理的
connect函數(shù)有五個參數(shù),第五個參數(shù)就是只有在多線程的時候才有意義,用于指定信號和槽的連接類型,同時影響信號的傳遞方式和槽函數(shù)的執(zhí)行順序
參數(shù) | 說明 |
---|---|
Qt::AutoConnection | 根據(jù)信號和槽函數(shù)所在的線程自動選擇連接類型,同一線程使用Qt::DirectConnection,不同線程使用Qt::UniqueConnection |
Qt::DirectConnection | 信號發(fā)出時,槽函數(shù)會立即在同一線程中執(zhí)行,適用于信號和槽在同一線程時 |
Qt::QueuedConnection | 信號發(fā)出時,槽函數(shù)會被插入到接收對象所屬的線程的事件隊列中,等待下一次時間循環(huán)時執(zhí)行,適用于信號和槽不在同一線程 |
Qt::BlockingQueuedConnection | 信號發(fā)出時,發(fā)送信號的線程會被阻塞,直到槽函數(shù)執(zhí)行完畢,適用于信號和槽不在同一線程 |
Qt::UniqueConnection | 確保信號與槽之間唯一連接關系的標志,可以使用位或操作與上述四種一種連接類型組合使用,可以避免重復連接 |
2、線程安全
(1)互斥鎖
互斥鎖是一種保護和防止多個線程同時訪問同一對象實例的辦法,主要通過QMutex類來處理
QMutex
用于保護共享資源的訪問,實現(xiàn)線程間的互斥操作,在多線程的環(huán)境下,通過互斥鎖來控制對共享數(shù)據(jù)的訪問,確保線程安全
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();//鎖上//每有一個線程進來就打印線程以及遞增的數(shù)字qDebug() << this <<" : " << this->num++;this->mutex.unlock();//解鎖QThread::sleep(1);}
}
在這個代碼塊中,mutex.lock() 和 mutex.unlock() 手動管理互斥鎖,每次打印完信息后立即釋放鎖,然后進行 QThread::sleep(1),由于鎖已經(jīng)釋放,其他線程可以立即進入這段代碼,導致線程的執(zhí)行和打印信息可能是無序的
void MyThread::run()
{while (1) {QMutexLocker locker(&mutex);qDebug() << this <<" : " << this->num++;QThread::sleep(1);}
}
在這個代碼塊中,使用了 QMutexLocker 來管理鎖,QMutexLocker 會在它的作用范圍內自動鎖定 mutex,并在 locker 離開作用域時(即循環(huán)的下一次迭代開始時)自動解鎖,在這里,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:讀寫鎖類,用于控制讀和寫的并發(fā)訪問
QReadLocker:讀操作上鎖,允許多個線程同時讀取共享資源
QWriteLocker:寫操作上鎖,只允許一個線程寫入共享資源
QReadWriteLock rwLock;//在讀操作中使?讀鎖
{QReadLocker locker(&rwLock); //在作?域內?動上讀鎖//讀取共享資源//...
}//在作?域結束時?動解讀鎖//在寫操作中使?寫鎖
{QWriteLocker locker(&rwLock); //在作?域內?動上寫鎖//修改共享資源//...
}//在作?域結束時?動解寫鎖
(2)條件變量
因為在多線程編程中,某些線程需要等待某些條件滿足才能執(zhí)行,此時線程會使用鎖的機制來阻塞其他線程,當條件滿足時,等待條件的線程將被另一個線程喚醒
QWaitCondition是Qt框架提供的條件變量類,用于線程之間的通信和同步,在某個條件滿足時等待或喚醒線程,用于線程的同步和協(xié)調
QMutex mutex;
QWaitCondition condition;//等待線程中
mutex.lock();//檢查條件是否滿足,不滿足就等待
while (!conditionFullfilled())
{condition.wait(&mutex);//條件滿足釋放鎖
}mutex.unlock();//------------------------------------------------------------------------------------//在改變條件的線程中
mutex.lock();
//改變條件
changeCondition();
condition.wakeAll(); //喚醒等待的線程mutex.unlock();
(3)信號量
QSemaphone是Qt框架提供的計數(shù)信號類,用于控制同時訪問共享資源的線程數(shù)量,用于限制并發(fā)線程數(shù)量,用于解決一些資源有限的問題
QSemaphore semaphore(2); //同時允許兩個線程訪問共享資源//在需要訪問共享資源的線程中
semaphore.acquire(); //嘗試獲取信號量,若已滿則阻塞//訪問共享資源
//...
semaphore.release(); //釋放信號量
//在另?個線程中也要進行類似操作
今日分享就到這了~