Qt互斥鎖(QMutex)的使用、QMutexLocker的使用

Qt互斥鎖【QMutex】的使用、QMutexLocker的使用

  • 基于讀寫鎖(QReadWriteLock)的線程同步
  • Chapter1 Qt互斥鎖(QMutex)的使用、QMutexLocker的使用
    • 一、QMutexLocker和QMutex實現示例圖
    • 二、QMutex和QMutexLocker的關系(個人理解)
    • 三、QMutex使用和QMutexLocker使用
      • 1.QMutex的使用
      • 2.QMutexLocker的使用
    • 四、檢驗QMutexLocker是否將傳入的互斥鎖鎖定
      • 1.操作解釋
      • 2.CMoveFuncClass(使用moveToThread實現,使用QMutexLocker)
      • 3.CThread類(繼承QThread實現,單純使用QMutex)
      • 4.CMainWindow調用類
    • 總結
    • 相關文章
  • Chapter2 QReadWriteLock讀寫鎖
    • 1、讀寫鎖的特性:讀共享,寫獨占。
    • 2、讀寫優先級
    • 3、常用函數包含:
    • 4、常關聯的類包含:
  • Chapter3 QT多線程(二):基于互斥鎖與讀寫鎖的線程同步
    • 1. 線程同步概念
    • 2. 基于互斥量的線程同步
      • 2.1 QMutex類
      • 2.2 QMutexLocker 類
    • 3. 基于讀寫鎖的線程同步


基于讀寫鎖(QReadWriteLock)的線程同步

使用互斥量時存在一個問題,即每次只能有一個線程獲得互斥量的使用權限。如果在一個程序中有多個線程讀取某個變量,使用互斥量時必須排隊。而實際上若只是讀取一個變量,可以讓多個線程同時訪問,這種情況下使用互斥量就會降低程序的性能。

因此提出了讀寫鎖概念,Qt 提供了讀寫鎖類 QReadWriteLock,它是基于讀或寫的方式進行代碼片段鎖定的,在多個線程讀寫一個共享數據時,使用它可以解決使用互斥量存在的上面所提到的問題。

QReadWriteLock 以 讀或寫鎖定的同步方法允許以讀或寫的方式保護一段代碼,它可以允許多個線程以只讀方式同步訪問資源,但是只要有一個線程在以寫入方式訪問資源,其他線程就必須等待,直到寫操作結束。

簡單總結就是:同一時間,多個線程可以同時讀,只有一個線程可以寫,讀寫不能同時進行。

Chapter1 Qt互斥鎖(QMutex)的使用、QMutexLocker的使用

原文鏈接:https://blog.csdn.net/wj584652425/article/details/123585126

一、QMutexLocker和QMutex實現示例圖

下圖為檢測QMutexLocker是否上鎖成功的示例圖(兩個線程使用同一個QMutex),源碼在文章第四節(源碼含詳細注釋)。

下圖為不同QMutex運行時的效果(該圖表明兩個線程無關,并非sleep影響了另一個線程的運行)

二、QMutex和QMutexLocker的關系(個人理解)

互斥鎖(QMutex)在使用時需要在進入和結束的時候使用對應的函數鎖定和解鎖。在簡單的程序中還好,但是在結構復雜的程序中因為需要手動鎖定和解鎖,很容易忽略細節而出現問題,于是為了應對這種情況QMutexLocker便誕生了(為了簡化簡化互斥鎖的鎖定和解鎖)。
QMutexLocker通常創建為局部變量,QMutexLocker在創建時傳入一個并未鎖定(若是鎖定可用relock重新鎖定或unlock解鎖)的QMutex指針變量,并且會將QMutex變量鎖定,在釋放時會將QMutex變量解鎖。(QMutexLocker創建時將傳入的QMutex鎖定,釋放時將傳入的QMutex解鎖)

三、QMutex使用和QMutexLocker使用

1.QMutex的使用

void CThread::run()
{//互斥鎖鎖定m_mutex->lock();//輸出當前線程的線程IDqDebug() << QThread::currentThreadId();//互斥鎖解鎖m_mutex->unlock();
}

2.QMutexLocker的使用

void CThread::run()
{//創建QMutexLocker的局部變量,并將類中互斥鎖指針傳入(此處互斥鎖被locker鎖定)QMutexLocker locker(m_mutex);qDebug() << QThread::currentThreadId();//當locker作用域結束locker將互斥鎖解鎖
}

通過1、2的代碼比較,我們會發現QMutexLocker的代碼中沒有手動調用鎖定和解鎖,由此可看出MutexLocker簡化了互斥鎖的鎖定和解鎖。

四、檢驗QMutexLocker是否將傳入的互斥鎖鎖定

1.操作解釋

使用兩種實現方法完全不同線程測試
兩個線程使用同一個互斥鎖
一個線程使用QMutexLocker一個線程單純使用QMutex

2.CMoveFuncClass(使用moveToThread實現,使用QMutexLocker)

CMoveFuncClass.h

#ifndef CMOVEFUNCCLASS_H
#define CMOVEFUNCCLASS_H#include <QObject>
#include <QMutex>class CMoveFuncClass : public QObject
{Q_OBJECT
public:explicit CMoveFuncClass(QObject *parent = nullptr);~CMoveFuncClass();void setMutex(QMutex *mutex);public slots:void doSomething();private:QMutex * m_mutex;   //定義一個互斥鎖變量
};#endif // CMOVEFUNCCLASS_H

CMoveFuncClass.cpp

#include "CMoveFuncClass.h"#include <QDebug>
#include <QThread>CMoveFuncClass::CMoveFuncClass(QObject *parent): QObject(parent)
{
}CMoveFuncClass::~CMoveFuncClass()
{
}void CMoveFuncClass::doSomething()
{//創建QMutexLocker的局部變量,并將類中互斥鎖指針傳入(此處互斥鎖被locker鎖定)QMutexLocker locker(m_mutex);qDebug() << "我的實現方法為moveToThread" <<"開始3秒睡眠" << "使用QMutexLocker";qDebug() << "線程ID:" << QThread::currentThreadId();QThread::sleep(3);  //設置線程睡眠3秒(單位為秒)qDebug() << "我的實現方法為moveToThread" <<"線程運行完成,結束睡眠\n\n";//當locker作用域結束locker將互斥鎖解鎖
}void CMoveFuncClass::setMutex(QMutex *mutex)
{m_mutex = mutex;
}

3.CThread類(繼承QThread實現,單純使用QMutex)

CThread.h

#ifndef CTHREAD_H
#define CTHREAD_H#include <QObject>
#include <QThread>
#include <QMutex>
#include <QWaitCondition>class CThread : public QThread
{Q_OBJECT
public:explicit CThread(QObject *parent = nullptr);~CThread();void run();void setMutex(QMutex *mutex);private:QMutex *            m_mutex;            //定義一個線程鎖變量};#endif // CTHREAD_H

CThread.cpp

#include "CThread.h"
#include <QDebug>CThread::CThread(QObject *parent): QThread(parent)
{
}CThread::~CThread()
{
}void CThread::run()
{//互斥鎖上鎖m_mutex->lock();qDebug() << "我的實現方法為繼承QThread" << "開始3秒睡眠" << "單純使用QMutex";qDebug() << "線程ID:" << QThread::currentThreadId();QThread::sleep(3);  //設置線程睡眠3秒(單位為秒)qDebug() << "我的實現方法為繼承QThread" <<"線程運行完成,結束睡眠";//互斥鎖解鎖m_mutex->unlock();
}void CThread::setMutex(QMutex *mutex)
{m_mutex = mutex;
}

4.CMainWindow調用類

CMainWindow.h

#ifndef CMAINWINDOW_H
#define CMAINWINDOW_H#include <QMainWindow>
#include "CThread.h"
#include "CMoveFuncClass.h"namespace Ui {
class CMainWindow;
}class CMainWindow : public QMainWindow
{Q_OBJECTpublic:explicit CMainWindow(QWidget *parent = 0);~CMainWindow();signals:void startMoveThread();private slots:void on_startBtn_clicked();		//觸發方法二函數的信號private:Ui::CMainWindow *ui;CThread         *m_cThread;		//方法一指針CMoveFuncClass  *m_moveFunc;	//方法二指針QThread         *m_thread;		//方法二所移至的線程指針QMutex          *m_mutex;       //兩個線程使用的線程鎖
};#endif // CMAINWINDOW_H

CMainWindow.cpp

#include "CMainWindow.h"
#include "ui_CMainWindow.h"#include <QDebug>CMainWindow::CMainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::CMainWindow)
{ui->setupUi(this);/方法一/////new出CThread對象m_cThread = new CThread;/方法二/////new一個moveToThread的接收線程并啟動m_thread = new QThread;//new出CMoveFuncClass對象m_thread->start();  //一定記得啟動,否則運行不了m_moveFunc = new CMoveFuncClass;//連接相應信號槽connect(this, &CMainWindow::startMoveThread, m_moveFunc, &CMoveFuncClass::doSomething);connect(m_thread, &QThread::finished, m_moveFunc, &QObject::deleteLater);//將對象移至線程m_moveFunc->moveToThread(m_thread);//創建線程共用的互斥鎖m_mutex = new QMutex;//下方為m_mutex的地方更改為new QMutex,則能實現第一節,第二張圖的效果m_cThread->setMutex(m_mutex);m_moveFunc->setMutex(m_mutex);
}CMainWindow::~CMainWindow()
{delete m_mutex;delete m_moveFunc;m_thread->exit();m_thread->wait(1);delete m_thread;m_cThread->exit();m_cThread->wait(1);delete m_cThread;delete ui;
}void CMainWindow::on_startBtn_clicked()
{//通過start啟動方法一線程m_cThread->start();//發送信號啟動方法二線程emit startMoveThread();
}

運行上方的代碼(第一節,第一張效果圖)可看出,使用QMutexLocker的線程首先運行,且代碼中無鎖定和解鎖的操作,但另外一個線程依然等該線程運行完成后運行,由此可看出,使用QMutexLocker是實現了互斥鎖的鎖定和解鎖的。

總結

QMutexLocker提供的簡化互斥鎖鎖定和解鎖的機制在很多時候時蠻方便的,在使用互斥鎖的地方使用QMutexLocker會減去許多安全隱患;不過在多線程循環輸出ABC的時候好像就不適合該方法。所以使用類似的類還得按情況而定

相關文章

啟動QThread線程的兩種方法(含源碼+注釋)
Qt互斥鎖(QMutex)、條件變量(QWaitCondition)講解+QMutex實現多線程循環輸出ABC(含源碼+注釋)
QSemaphore的使用+QSemaphore實現循環輸出ABC(含源碼+注釋)
QRunnable線程、QThreadPool(線程池)的使用(含源碼+注釋)
Qt讀寫鎖(QReadWriteLock)的使用、讀寫鎖的驗證(含源碼+注釋)
Qt讀寫鎖(QWriteLocker、QReadLocker)的理解和使用(含部分源碼)
Qt之線程運行指定函數(含源碼+注釋,優化速率)

友情提示——哪里看不懂可私哦,讓我們一起互相進步吧
(創作不易,請留下一個免費的贊叭 謝謝 o/)

注:文章為作者編程過程中所遇到的問題和總結,內容僅供參考,若有錯誤歡迎指出。
注:如有侵權,請聯系作者刪除

Chapter2 QReadWriteLock讀寫鎖

原文鏈接:https://blog.csdn.net/weixin_43246170/article/details/121015495

QT中線程間的同步分別有QMutex互斥鎖、QSemephone信號量、QWaitCondition條件變量和QReadWriteLock讀寫鎖四種方式。

這邊來介紹的是讀寫鎖,一般應用與具有大量讀操作的場景。

1、讀寫鎖的特性:讀共享,寫獨占。

讀共享 :
當其他線程占用讀鎖的時候,如果其他線程請求讀鎖,會立即獲得。
當其他線程占用讀鎖的時候,如果其他線程請求寫鎖,會阻塞等待讀鎖的釋放。
寫獨占 :
當其他線程占用寫鎖的時候,如果其他線程請求讀鎖,會阻塞等待寫鎖的釋放。
當其他線程占用寫鎖的時候,如果其他線程請求寫鎖,會阻塞等待寫鎖的釋放。

2、讀寫優先級

默認優先級是寫優先,即寫鎖的優先級>讀鎖,哪怕是讀先排隊的也沒用。

3、常用函數包含:

lockForRead() ; 請求讀鎖
lockForWrite() ; 請求寫鎖
tryLockForRead() ; 嘗試請求讀鎖,非阻塞函數,可以設置超時時間。
tryLockForWrite() ; 嘗試請求寫鎖,非阻塞函數,可以設置超時時間。
unlock() ; 解鎖(解讀鎖和解寫鎖,均使用該函數)

4、常關聯的類包含:

QReadLocker;
QWriteLocker;

Chapter3 QT多線程(二):基于互斥鎖與讀寫鎖的線程同步

原文鏈接:https://blog.csdn.net/qq_46144191/article/details/144494017

此處需要說明的是,這里的線程同步概念與操作系統中的線程同步并無區別,都是避免多個線程同時訪問臨界區數據可能產生的讀寫錯誤問題。在 Qt 中,有多個類可以實現線程同步的功能,這些類包括 QMutex、QMutexLocker、 QReadWriteLock、QReadLocker、QWriteLocker、QWaitCondition、QSemaphore 等。

1. 線程同步概念

在多線程程序中,由于存在多個線程,線程之間可能需要訪問同一個變量,或一個線程需要等待另一個線程完成某個操作后才產生相應的動作。例如在上一節中提到的例程,工作線程生成隨機的骰子點數,主線程讀取骰子點數并顯示,主線程需要等待工作線程生成一新的骰子點數后再讀取數據。但上一節中并沒有使用線程同步機制,而是使用了信號與槽的機制,在生成新的點數之后通過

信號通知主線程讀取新的數據。這個過程類似于操作系統的線程信號機制,都是為信號設定一個處理函數,本章中不使用信號與槽函數來講解其他方式的線程同步方法。

2. 基于互斥量的線程同步

QMutex 和 QMutexLocker 是基于互斥量(mutex)的線程同步類。

2.1 QMutex類

該類提供的API函數如下:

void QMutex::lock() //鎖定互斥量,一直等待
void QMutex::unlock() //解鎖互斥量
bool QMutex::tryLock() //嘗試鎖定互斥量,不等待
bool QMutex::tryLock(int timeout) //嘗試鎖定互斥量,最多等待 timeout 毫秒

函數 lock()鎖定互斥量,如果另一個線 程鎖定了這個互斥量,它將被阻塞運行直到 其他線程解鎖這個互斥量。函數 unlock()解鎖互斥量,需要與 lock()配對使用。

函數 tryLock()嘗試鎖定一個互斥量,如果成功鎖定就返回 true,如果其他線程已經鎖定了這個互斥量就返回 false。函數 tryLock(int timeout)嘗試鎖定一個互斥量,如果這個互斥量被其他線程鎖定,最多等待 timeout 毫秒。

互斥量相當于一把鑰匙,如果兩個線程要訪問同一個共享資源,就需要通過 lock()或 tryLock()拿到這把鑰匙,然后才可以訪問該共享資源,訪問完之后還要通過unlock()還回鑰匙,這樣別的線程才有機會拿到鑰匙。

在這里插入圖片描述

在上一節的例程中,在TDiceThread類中添加一個QMutex變量,并刪除自定義信號newValue(),增加一個readValue()函數用于提供給主窗口訪問類變量。

QMutex  mutex;  //互斥量bool TDiceThread::readValue(int *seq, int *diceValue)
{if (mutex.tryLock(100))  //嘗試鎖定互斥量,等待100ms{*seq=m_seq;*diceValue=m_diceValue;mutex.unlock();     //解鎖互斥量return true;}elsereturn false;
}

主函數(主線程)在訪問m_seq和m_diceValue變量時,會嘗試獲取“鑰匙”,最多等待100ms,得到權限后會通過指針類變量返回值。事后解鎖以便于工作線程對這兩個變量進行修改。

另一處需修改的是工作線程中的訪問,代碼如下:

void TDiceThread::run()
{//線程的事件循環m_stop=false;       //啟動線程時令m_stop=falsem_paused=true;      //啟動運行后暫時不擲骰子m_seq=0;            //擲骰子次數while(!m_stop)      //循環主體{if (!m_paused){mutex.lock();       //鎖定互斥量m_diceValue=0;for(int i=0; i<5; i++)m_diceValue += QRandomGenerator::global()->bounded(1,7);  //產生隨機數[1,6]m_diceValue =m_diceValue/5;m_seq++;mutex.unlock();     //解鎖互斥量}msleep(500);    //線程休眠500ms}quit();     //在  m_stop==true時結束線程任務
}

在函數 run()中,我們對重新計算變量 m_diceValue 和 m_seq 值的代碼片段用互斥量 mutex 進行了保護。工作線程運行后,其內部的函數 run()一直在運行。主線程里調用工作線程的 readValue()函數,其實際是在主線程里運行的。

通過上述方式,主線程和工作線程都對臨界區的變量進行了互斥訪問,這樣就可確保數據的完整性。

2.2 QMutexLocker 類

QMutexLocker 是另一個簡化了互斥量處理的類。QMutexLocker 的構造函數接受互斥量作為參數并將其鎖定,QMutexLocker 的析構函數則將此互斥量解鎖,所以在 QMutexLocker 實例變量的生存期內的代碼片段會得到保護,自動進行互斥量的鎖定和解鎖。

void TDiceThread::run()
{//線程的事件循環m_stop=false;       //啟動線程時令m_stop=falsem_paused=true;      //啟動運行后暫時不擲骰子m_seq=0;            //擲骰子次數while(!m_stop)      //循環主體{if (!m_paused){QMutexLocker locker(&mutex);m_diceValue=0;for(int i=0; i<5; i++)m_diceValue += QRandomGenerator::global()->bounded(1,7);  //產生隨機數[1,6]m_diceValue =m_diceValue/5;m_seq++;}msleep(500);    //線程休眠500ms}quit();     //在  m_stop==true時結束線程任務
}

這兩種實現互斥訪問的功能一樣,使用是分別注意其形式即可。

在主窗口類的構造函數中,設置了一個定時器,每隔一段時間讀取一次臨界區變量,如果成功獲取到鎖并且數據也是最新的,則據此更新主界面。

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);threadA= new TDiceThread(this);connect(threadA,&TDiceThread::started, this, &MainWindow::do_threadA_started);connect(threadA,&TDiceThread::finished,this, &MainWindow::do_threadA_finished);timer= new QTimer(this);     //創建定時器timer->setInterval(200);timer->stop();connect(timer,&QTimer::timeout, this, &MainWindow::do_timeOut);
}void MainWindow::do_timeOut()
{int tmpSeq=0,tmpValue=0;bool  valid=threadA->readValue(&tmpSeq,&tmpValue); //讀取數值if (valid && (tmpSeq != m_seq)) //有效,并且是新數據{m_seq=tmpSeq;m_diceValue=tmpValue;QString  str=QString::asprintf("第 %d 次擲骰子,點數為:%d",m_seq,m_diceValue);ui->plainTextEdit->appendPlainText(str);QString filename=QString::asprintf(":/dice/images/d%d.jpg",m_diceValue);QPixmap pic(filename);ui->labPic->setPixmap(pic);}}

在開始和結束按鈕槽函數中,需要設置定時器的啟動和停止。代碼如下:

void MainWindow::on_actDice_Run_triggered()
{//"開始"按鈕,開始擲骰子threadA->diceBegin();timer->start();     //重啟定時器ui->actDice_Run->setEnabled(false);ui->actDice_Pause->setEnabled(true);
}void MainWindow::on_actDice_Pause_triggered()
{//"暫停"按鈕,暫停擲骰子threadA->dicePause();timer->stop();      //停止定時器ui->actDice_Run->setEnabled(true);ui->actDice_Pause->setEnabled(false);
}

3. 基于讀寫鎖的線程同步

使用互斥量時存在一個問題,即每次只能有一個線程獲得互斥量的使用權限。如果在一個程序中有多個線程讀取某個變量,使用互斥量時必須排隊。而實際上若只是讀取一個變量,可以讓多個線程同時訪問,這種情況下使用互斥量就會降低程序的性能。

因此提出了讀寫鎖概念,Qt 提供了讀寫鎖類 QReadWriteLock,它是基于讀或寫的方式進行代碼片段鎖定的,在多個線程讀寫一個共享數據時,使用它可以解決使用互斥量存在的上面所提到的問題。

QReadWriteLock 以 讀或寫鎖定的同步方法允許以讀或寫的方式保護一段代碼,它可以允許多個線程以只讀方式同步訪問資源,但是只要有一個線程在以寫入方式訪問資源,其他線程就必須等待,直到寫操作結束。

簡單總結就是:同一時間,多個線程可以同時讀,只有一個線程可以寫,讀寫不能同時進行。

QReadWriteLock類 提供以下幾個主要的函數:

void lockForRead() //以只讀方式鎖定資源,如果有其他線程以寫入方式鎖定資源,這個函數會被阻塞
void lockForWrite() //以寫入方式鎖定資源,如果其他線程以讀或寫方式鎖定資源,這個函數會被阻塞
void unlock() //解鎖
bool tryLockForRead() //嘗試以只讀方式鎖定資源,不等待
bool tryLockForRead(int timeout) //嘗試以只讀方式鎖定資源,最多等待 timeout 毫秒
bool tryLockForWrite() //嘗試以寫入方式鎖定資源,不等待
bool tryLockForWrite(int timeout) //嘗試以寫入方式鎖定資源,最多等待 timeout 毫秒

例如下列案例:

int buffer[100]; 
QReadWriteLock Lock; //定義讀寫鎖變量
void ThreadDAQ::run() //負責采集數據的線程
{ ... Lock.lockForWrite(); //以寫入方式鎖定get_data_and_write_in_buffer(); //數據寫入 buffer Lock.unlock();... 
} 
void ThreadShow::run() //負責顯示數據的線程
{ ... Lock.lockForRead(); //以讀取方式鎖定show_buffer(); //讀取 buffer 里的數據并顯示Lock.unlock(); ... 
} 
void ThreadSaveFile::run() //負責保存數據的線程
{ ... Lock.lockForRead(); //以讀取方式鎖定save_buffer_toFile(); //讀取 buffer 里的數據并保存到文件Lock.unlock(); ... 
}

另外,QReadLocker 和 QWriteLocker 是 QReadWriteLock 的簡便形式,如同 QMutexLocker 是 QMutex 的簡便形式一樣,無須與 unlock()配對使用。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/71184.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/71184.shtml
英文地址,請注明出處:http://en.pswp.cn/web/71184.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【無標題】Ubuntu22.04編譯視覺十四講slambook2 ch4時fmt庫的報錯

Ubuntu22.04編譯視覺十四講slambook2 ch4時fmt庫的報錯 cmake ..順利&#xff0c;make后出現如下報錯&#xff1a; in function std::make_unsigned<int>::type fmt::v8::detail::to_unsigned<int>(int): trajectoryError.cpp:(.text._ZN3fmt2v86detail11to_unsi…

SpringBoot ——簡單開發流程實戰

本文使用SpringBoot進行電商系統商品數據增刪改查的簡單開發流程。 本文目錄 一、創建Spring Boot項目二、配置數據庫連接三、創建實體類四、創建Repository接口五、創建Service層六、創建Controller層七、測試 一、創建Spring Boot項目 可以通過https://start.spring.io/或者…

fastadmin 后臺商品sku(vue)

先上個效果圖 首先先引入vue define([backend], function (Backend) {require.config({paths: {vue: /assets/jeekshopskugoods/libs/vue.min,skuimg: /assets/jeekshopskugoods/js/skuimg,skugoods: /assets/jeekshopskugoods/js/skugoods,layui: /assets/LayuiSpzj/layui/la…

LeetCode 718 - 最長重復子數組

LeetCode 718 - 最長重復子數組 是一個典型的數組和字符串問題&#xff0c;適合考察動態規劃、滑動窗口和二分查找等多種編程能力。掌握其多種解法及變體能夠有效提高處理字符串和數組算法的能力。 題目描述 輸入: 兩個整數數組 nums1 和 nums2。輸出: 兩個數組中存在的最長的…

LeetCode 0132.分割回文串 II:動態規劃

【LetMeFly】132.分割回文串 II&#xff1a;動態規劃 力扣題目鏈接&#xff1a;https://leetcode.cn/problems/palindrome-partitioning-ii/ 給你一個字符串 s&#xff0c;請你將 s 分割成一些子串&#xff0c;使每個子串都是回文串。 返回符合要求的 最少分割次數 。 示例 …

iOS 實現UIButton自動化點擊埋點

思路&#xff1a;我們HOOK UIControl的 addtarget:action:forControlEvents方法&#xff0c;交換UIControl的 addtarget:action:forControlEvents 方法的實現&#xff0c; 在交換的方法中添加原來響應的同時&#xff0c;再添加一個埋點響應&#xff0c;該響應方法實現了點擊埋點…

C++藍橋杯基礎篇(六)

片頭 嗨~小伙伴們&#xff0c;大家好&#xff01;今天我們來一起學習藍橋杯基礎篇&#xff08;六&#xff09;&#xff0c;練習相關的數組習題&#xff0c;準備好了嗎&#xff1f;咱們開始咯&#xff01; 第1題 數組的左方區域 這道題&#xff0c;實質上是找規律&#xff0c;…

git -學習筆記

目錄 基本操作語法 設置用戶和郵箱 版本回退 工作區和暫存區 撤銷修改 刪除與恢復 一工作區刪除了&#xff0c;但是暫存區沒刪除 二工作區誤刪了&#xff0c;暫存區還有 github-Git 連接 報錯解決-push遠程倉庫被拒絕 遠程庫 分支 分支沖突 儲藏分支 回到當前分…

Windows本地Docker+Open-WebUI部署DeepSeek

最近想在自己的電腦本地部署一下DeepSeek試試&#xff0c;由于不希望污染電腦的Windows環境&#xff0c;所以在wsl中安裝了ollama&#xff0c;使用ollama拉取DeepSeek模型。然后在Windows中安裝了Docker Desktop&#xff0c;在Docker中部署了Open-WebUI&#xff0c;最后再在Ope…

力扣785. 判斷二分圖

力扣785. 判斷二分圖 題目 題目解析及思路 題目要求將所有節點分成兩部分&#xff0c;每條邊的兩個端點都必須在不同集合中 二分圖&#xff1a;BFS/DFS/并查集 因為圖不一定聯通&#xff0c;所以枚舉所有點都做bfs(如果沒聯通的話) 代碼 class Solution { public:bool is…

springboot之集成Elasticsearch

目錄 二、Elasticsearch 是什么&#xff1f;三、Elasticsearch 安裝四、Springboot 集成 Elasticsearch 的方式五、創建項目集成 Elasticsearch 2.創建 Spring Initializr 項目 es &#xff08;3&#xff09;.新建實體類 User&#xff08;4&#xff09;.新建 dao 接口類 UserR…

[Lc滑動窗口_1] 長度最小的數組 | 無重復字符的最長子串 | 最大連續1的個數 III | 將 x 減到 0 的最小操作數

目錄 1. 長度最小的字數組 題解 代碼 ?2.無重復字符的最長子串 題解 代碼 3.最大連續1的個數 III 題解 代碼 4.將 x 減到 0 的最小操作數 題解 代碼 1. 長度最小的字數組 題目鏈接&#xff1a;209.長度最小的字數組 題目分析: 給定一個含有 n 個 正整數 的數組…

數據集筆記:新加坡 地鐵(MRT)和輕軌(LRT)票價

數據連接 data.gov.sg 2024 年 12 月 28 日起生效的新加坡地鐵票價 該數據集包含 MRT 和 LRT 票價的信息&#xff0c;包括&#xff1a; 票價類型&#xff08;Fare Type&#xff09;&#xff1a;成人票、學生票、老年人票、殘障人士票等。適用時間&#xff08;Applicable Tim…

湘潭大學計算機復試詳細攻略(調劑)

一&#xff0c;寫在前面的話 ① 首先&#xff0c;能完成考試初試來到這里的都是勇士。不管結果如何&#xff0c;不管成績如何。我都在這里真心的祝福你以后一帆風順。 ② 目前學歷貶值嚴重&#xff0c;如果是成績不理想的話&#xff0c;我建議能工作就去工作&#xff0c;工作不…

【前端基礎】Day 3 CSS-2

目錄 1. Emmet語法 1.1 快速生成HTML結構語法 1.2 快速生成CSS樣式語法 2. CSS的復合選擇器 2.1 后代選擇器 2.2 子選擇器 2.3 并集選擇器 2.4 偽類選擇器 2.4.1 鏈接偽類選擇器 2.4.2 focus偽類選擇器 2.5 復合選擇器總結 3. CSS的元素顯示模式 3.1 什么是元素顯示…

不同數據類型在數據庫和編程語言之間的對應關系表

不同數據類型在數據庫和編程語言之間的對應關系表 MySql 與 C# MySqlC#varcharstringbigintlongbigint unsignedulongintintint unsigneduintsmallintshortsmallint unsignedushortVARCHAR(36)GuidsmalldatetimeDateTimedateDateTimedatetimeDateTimetimestampDateTimefloatf…

RabbitMQ操作實戰

1.RabbitMQ安裝 RabbitMQ Windows 安裝、配置、使用 - 小白教程-騰訊云開發者社區-騰訊云下載erlang&#xff1a;http://www.erlang.org/downloads/https://cloud.tencent.com/developer/article/2192340 Windows 10安裝RabbitMQ及延時消息插件rabbitmq_delayed_message_exch…

DeepSeek教unity------UI元素長按響應

主要功能說明&#xff1a; ?長按檢測&#xff1a;通過記錄指針按下的時間&#xff0c;判斷是否達到 longClickTime&#xff0c;從而觸發長按事件。?狀態管理&#xff1a;使用 StateEnum 枚舉管理點擊項的當前狀態&#xff08;未按下、按下等待長按、長按已觸發&#xff09;。…

【北京迅為】itop-3568 開發板openharmony鴻蒙燒寫及測試-第2章OpenHarmony v3.2-Beta4版本測試

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工藝&#xff0c;搭載一顆四核Cortex-A55處理器和Mali G52 2EE 圖形處理器。RK3568 支持4K 解碼和 1080P 編碼&#xff0c;支持SATA/PCIE/USB3.0 外圍接口。RK3568內置獨立NPU&#xff0c;可用于輕量級人工…

stm32hal庫尋跡+藍牙智能車(STM32F103C8T6)

簡介: 這個小車的芯片是STM32F103C8T6&#xff0c;其他的芯片也可以照貓畫虎,基本配置差不多,要注意的就是,管腳復用,管腳的特殊功能,(這點不用擔心,hal庫每個管腳的功能都會給你羅列,很方便的.)由于我做的比較簡單,只是用到了幾個簡單外設.主要是由帶霍爾編碼器電機的車模,電機…