qt-C++筆記之QThread使用

qt-C++筆記之QThread使用

——2024-05-26 下午

在這里插入圖片描述

在這里插入圖片描述

code review!

參考博文:
qt-C++筆記之使用QtConcurrent異步地執行槽函數中的內容,使其不阻塞主界面
qt-C++筆記之QThread使用

文章目錄

  • qt-C++筆記之QThread使用
    • 一:Qt中幾種多線程方法
      • 1.1. 使用 `QThread` 和 Lambda
      • 1.2. 使用 `QThread::create()`
      • 1.3. 繼承 `QThread` 并重寫 `run()`
      • 1.4. 使用 `QObject` 派生類與 `QThread`
      • 1.5. 使用 `QtConcurrent::run()`
      • 總結
    • 二.方法一:繼承QThread并重寫其run()方法
      • 2.1.代碼一:運行全局純函數
      • 2.2.代碼二:運行全局純函數
      • 2.3.代碼一和代碼二的區別
        • 2.3.1 帶`input`參數的構造函數
        • 2.3.2. 帶`input`和`parent`參數的構造函數
        • 2.3.3 總結
      • 2.4.代碼三:直接在run()方法中寫運行邏輯
      • 2.5.代碼四:直接在run()方法中寫運行邏輯,并在QCoreApplication::quit()前執行一些打印
      • 2.6.代碼五:通過繼承QThread的方式來運行一個純函數,并將參數通過類的成員變量傳遞給這個函數
      • 2.7.代碼六:通過繼承QThread的方式來運行一個純函數,并將參數通過類的成員變量傳遞給這個函數
    • 三.方法二:將任務放在QObject派生類中,并`moveToThread()`在QThread中運行這個QObject
      • 3.1. 代碼一:運行成員函數例程,讓 Worker 類繼承自 QObject,然后使用一個 QThread 實例來在另一個線程中運行這個 Worker 對象
      • 3.2. 代碼二:運行成員函數例程,讓 Worker 類繼承自 QObject,然后使用一個 QThread 實例來在另一個線程中運行這個 Worker 對象
    • 四.方法三:直接使用 QThread 和 Lambda
    • 五.方法四:`QThread::create(Qt 5.10 及以上)`
      • 5.1.提要
        • 5.1.1.QThread::create()代碼一
        • 5.1.2.QThread::create()代碼二
    • 六.方法五:`QtConcurrent::run()`

一:Qt中幾種多線程方法

五種不同的多線程實現方法在Qt中的特點和適用場景:

方法描述優點缺點適用場景
直接使用 QThread 和 Lambda使用 QThread 對象和信號槽連接一個lambda表達式來執行代碼。簡單快速;靈活定義啟動行為。精細控制線程較少;線程復用不便。快速實現簡單的后臺任務,不需要復用線程。
使用 QThread::create()使用 QThread::create() 創建并自動啟動線程來執行函數或lambda。極簡代碼;自動線程管理。對線程的控制較為有限;不易于復用。適合快速啟動一次性后臺任務,不需要線程間交互。
繼承 QThread 并重寫 run()通過繼承 QThread 并重寫其 run() 方法來定義線程行為。完全控制線程行為;能夠處理復雜邏輯。實現復雜;易誤用(如直接操作GUI)。需要精細控制線程行為或有復雜線程邏輯的場景。
使用 QObject 派生類與 QThread創建 QObject 派生類,并在移至 QThread 的對象上執行任務。分離工作和線程管理;完全的信號和槽支持。設置相對繁瑣;代碼量較多。需要線程頻繁與主線程通信或任務較為復雜的場景。
使用 QtConcurrent::run()使用Qt并發模塊的 QtConcurrent::run() 在線程池中運行函數或成員函數。簡單易用;自動管理線程池;減少資源消耗。對線程控制較少;不適合特定線程管理需求。適用于執行獨立的并發任務,不需要細粒度線程控制。

1.1. 使用 QThread 和 Lambda

這種方法直接使用 QThread 的實例,并通過信號和槽系統將lambda表達式綁定至 QThread::started 信號。這種方法允許靈活地定義線程開始時執行的代碼,而不需創建額外的類或使用 QtConcurrent。它適合快速簡單的線程使用,尤其是當你不需要頻繁與主線程通信或管理復雜的線程生命周期時。

1.2. 使用 QThread::create()

QThread::create() 是Qt 5.10引入的一個便捷函數,它基本上是創建線程與綁定任務的簡化版。你只需要提供一個函數或lambda表達式,QThread::create() 會自動創建線程并在啟動線程時執行這個函數。

auto thread = QThread::create([](){// 執行一些任務
});
thread->start();

這種方法的優點是極其簡單,但它通常不適用于需要復雜線程管理或多次復用線程的場景。

1.3. 繼承 QThread 并重寫 run()

這是一種更傳統的方法,通過繼承 QThread 并重寫其 run() 方法實現。這種方法提供了最大的靈活性,允許你控制線程的準確行為,但也需要更多的代碼和復雜的錯誤處理。

class WorkerThread : public QThread
{
protected:void run() override {// 執行任務}
};

1.4. 使用 QObject 派生類與 QThread

這是Qt推薦的多線程使用方式。你創建一個 QObject 派生類來封裝工作任務,然后將這個對象的實例移動到 QThread 中。

class Worker : public QObject
{Q_OBJECT
public slots:void doWork() {// 執行任務}
};QThread *thread = new QThread();
Worker *worker = new Worker();
worker->moveToThread(thread);
connect(thread, &QThread::started, worker, &Worker::doWork);
thread->start();

這種方法適合需要線程與主線程頻繁交互的場景,因為它完全兼容Qt的信號與槽機制。

1.5. 使用 QtConcurrent::run()

QtConcurrent::run() 是處理并發運算的另一種高級方法,它可以非常方便地在后臺線程池中運行函數或成員函數。

QtConcurrent::run([](){// 執行某些操作
});

這種方法非常適合不需要細粒度控制線程行為的場景,且可以自動管理線程池,避免創建和銷毀線程的開銷。

總結

  • 直接使用 QThread 和 Lambda:適合快速、一次性的簡單后臺任務。
  • 使用 QThread::create():簡化版的線程創建和任務綁定,適合不需要復用線程的場景。
  • 繼承 QThread:適用于需要完全控制線程行為的復雜場景。
  • 使用 QObject 派生類與 QThread:Qt推薦的方式,適合需要線程間頻繁通信的場景。
  • 使用 QtConcurrent::run():適用于簡單并發任務,自動線程池管理,減少資源消耗。

二.方法一:繼承QThread并重寫其run()方法

2.1.代碼一:運行全局純函數

#include <QCoreApplication>
#include <QThread>
#include <QDebug>// 純函數的定義,這個函數只進行計算并返回結果,不涉及任何的狀態修改
int pureFunction(int x) {return x * x;
}// 創建一個線程類,用于運行純函數
class WorkerThread : public QThread {
public:WorkerThread(int input) : inputValue(input) {}protected:void run() override {int result = pureFunction(inputValue);qDebug() << "計算結果:" << result;}private:int inputValue;
};int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);// 初始化一個線程對象,傳入參數5WorkerThread thread(5);// 連接線程的finished信號到QCoreApplication的quit槽,確保應用程序在線程結束后退出QObject::connect(&thread, &QThread::finished, &a, &QCoreApplication::quit);// 啟動線程thread.start();// 進入事件循環return a.exec();
}

運行

計算結果: 25

2.2.代碼二:運行全局純函數

#include <QCoreApplication>
#include <QThread>
#include <QDebug>// 全局純函數
void globalPureFunction(int param) {qDebug() << "運行在線程:" << QThread::currentThreadId();qDebug() << "接收到的參數:" << param;// 模擬一些處理過程QThread::sleep(2); // 假裝我們在做一些耗時的工作qDebug() << "處理完成";
}// 線程類
class WorkerThread : public QThread {int m_param;
public:WorkerThread(int param, QObject *parent = nullptr) : QThread(parent), m_param(param) {}protected:void run() override {globalPureFunction(m_param); // 在新線程中調用全局純函數}
};// 主函數
int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);int inputValue = 42; // 示例參數值WorkerThread *thread = new WorkerThread(inputValue);thread->start(); // 啟動線程QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater);QObject::connect(thread, &QThread::finished, &a, &QCoreApplication::quit);return a.exec();
}

運行

運行在線程: 0x7fd2ea57f700
接收到的參數: 42
處理完成

2.3.代碼一和代碼二的區別

在Qt中,處理QThread和其他繼承自QObject的類時,構造函數中的parent參數非常關鍵,它影響對象的內存管理和事件傳遞機制。讓我們比較一下這兩種構造函數的定義和它們的實際用途:

2.3.1 帶input參數的構造函數
WorkerThread(int input) : inputValue(input) {}

這個構造函數只接受一個input參數,并初始化成員變量inputValue。這里沒有顯式地處理parent參數:

  • 作用:初始化inputValue
  • 內存管理:這個WorkerThread對象的生命周期需要顯式管理(比如通過在堆上創建和刪除,或者確保其作用域在使用中不會結束),因為沒有父對象來自動管理它。
  • 適用場景:當你不需要將線程對象的生命周期與其他Qt對象關聯時,或者當你想要通過代碼顯式管理線程的生命周期時使用。
2.3.2. 帶inputparent參數的構造函數
WorkerThread(int input, QObject *parent = nullptr) : QThread(parent), inputValue(input) {}

這個構造函數接受一個input參數和一個可選的parent參數,默認為nullptr。它在初始化列表中調用了QThread的構造函數,傳遞了parent參數:

  • 作用:初始化inputValue并設置父對象。
  • 內存管理:如果指定了父對象(parent不為nullptr),這個WorkerThread對象的生命周期將由其父對象自動管理(父對象銷毀時,它也會被銷毀)。如果parentnullptr,則其生命周期需要手動管理。
  • 適用場景:當你希望線程的生命周期與某個Qt對象(如窗口或其他組件)綁定時使用。這樣可以簡化內存管理,使線程的生命周期與其父對象相匹配。
2.3.3 總結

添加parent參數的版本提供了更靈活的內存管理選項,允許線程對象以樹形層次結構中的一部分被管理,這對于復雜的Qt應用程序來說非常有用。沒有parent參數的版本則簡單、直接,更適合生命周期管理相對明確或簡單的場合。在實際應用中,選擇哪種方式取決于你的具體需求和線程管理策略。

2.4.代碼三:直接在run()方法中寫運行邏輯

#include <QCoreApplication>
#include <QThread>
#include <iostream>// WorkerThread 類,繼承自 QThread
class WorkerThread : public QThread
{
public:WorkerThread(QObject *parent = nullptr) : QThread(parent) {}// 重載 run 方法void run() override {// 純函數任務內容for (int i = 0; i < 10; ++i) {std::cout << "工作線程運行中: " << i << std::endl;QThread::sleep(1); // 模擬耗時操作,每次循環暫停1秒}std::cout << "工作線程結束運行。" << std::endl;}
};int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);// 創建 WorkerThread 對象WorkerThread thread;// 連接線程完成信號到退出槽,確保線程完成后應用程序退出QObject::connect(&thread, &WorkerThread::finished, &a, &QCoreApplication::quit);// 啟動線程thread.start();// 進入 Qt 事件循環return a.exec();
}

運行

工作線程運行中: 0
工作線程運行中: 1
工作線程運行中: 2
工作線程運行中: 3
工作線程運行中: 4
工作線程運行中: 5
工作線程運行中: 6
工作線程運行中: 7
工作線程運行中: 8
工作線程運行中: 9
工作線程結束運行。

2.5.代碼四:直接在run()方法中寫運行邏輯,并在QCoreApplication::quit()前執行一些打印

#include <QCoreApplication>
#include <QThread>
#include <QDebug>// 純函數,作為線程任務
void runTask() {for (int i = 0; i < 10; ++i) {QThread::sleep(1); // 模擬耗時任務qDebug() << "工作在線程 " << QThread::currentThreadId() << " 中執行: " << i;}
}// 自定義的線程類
class TaskThread : public QThread {Q_OBJECT // 添加 Q_OBJECT 宏以支持信號和槽
public:TaskThread(QObject *parent = nullptr) : QThread(parent) {}protected:void run() override {runTask(); // 在新線程中運行純函數emit taskCompleted(); // 發射任務完成信號}signals:void taskCompleted();
};int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);TaskThread thread;QObject::connect(&thread, &TaskThread::taskCompleted, &a, [&]() {qDebug() << "任務完成,信號在主線程 " << QThread::currentThreadId() << " 中被處理";QCoreApplication::quit(); // 完成后退出程序});qDebug() << "主線程ID: " << QThread::currentThreadId();thread.start(); // 啟動線程return a.exec();
}#include "main.moc" // 如果你不是使用 qmake,確保 moc 處理這個文件

運行

主線程ID:  0x7f7e73b0d780
工作在線程  0x7f7e6ef9d700  中執行:  0
工作在線程  0x7f7e6ef9d700  中執行:  1
工作在線程  0x7f7e6ef9d700  中執行:  2
工作在線程  0x7f7e6ef9d700  中執行:  3
工作在線程  0x7f7e6ef9d700  中執行:  4
工作在線程  0x7f7e6ef9d700  中執行:  5
工作在線程  0x7f7e6ef9d700  中執行:  6
工作在線程  0x7f7e6ef9d700  中執行:  7
工作在線程  0x7f7e6ef9d700  中執行:  8
工作在線程  0x7f7e6ef9d700  中執行:  9
任務完成,信號在主線程  0x7f7e73b0d780  中被處理

2.6.代碼五:通過繼承QThread的方式來運行一個純函數,并將參數通過類的成員變量傳遞給這個函數

#include <QCoreApplication>
#include <QThread>
#include <QDebug>// 純函數,有傳參
int square(int x) {return x * x;
}// 繼承QThread的類,重寫run()函數
class MyThread : public QThread {
protected:void run() override {// 調用純函數,并傳參int result = square(x);qDebug() << "Result:" << result;}public:int x;
};int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);// 創建MyThread對象MyThread thread;// 在main函數中聲明參數,并傳入MyThread對象int param = 10;thread.x = param;// 啟動MyThread對象thread.start();// 等待MyThread對象結束thread.wait();return a.exec();
}

運行

Result: 100

2.7.代碼六:通過繼承QThread的方式來運行一個純函數,并將參數通過類的成員變量傳遞給這個函數

#include <QCoreApplication>
#include <QThread>
#include <QDebug>// 純函數的聲明
void pureFunction(int a, int b);// 繼承自 QThread 的類
class WorkerThread : public QThread {public:// 構造函數WorkerThread(int a, int b, QObject *parent = nullptr) : QThread(parent), m_a(a), m_b(b) {}protected:// 重寫 run 方法void run() override {// 在新線程中調用純函數qDebug() << "線程開始執行";pureFunction(m_a, m_b);qDebug() << "線程執行完成";}private:int m_a, m_b;  // 成員變量,用于存儲傳遞給純函數的參數
};// 純函數的實現
void pureFunction(int a, int b) {// 執行一些計算或處理int result = a + b;qDebug() << "純函數執行結果:" << result;
}int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);// 創建 WorkerThread 對象,傳遞參數給純函數WorkerThread thread(10, 20);// 啟動線程thread.start();// 等待線程執行完成thread.wait();return a.exec();
}

運行

線程開始執行
純函數執行結果: 30
線程執行完成

三.方法二:將任務放在QObject派生類中,并moveToThread()在QThread中運行這個QObject

3.1. 代碼一:運行成員函數例程,讓 Worker 類繼承自 QObject,然后使用一個 QThread 實例來在另一個線程中運行這個 Worker 對象

// 包含必要的頭文件
#include <QCoreApplication>
#include <QThread>
#include <QDebug>// Worker 類定義
class Worker : public QObject {Q_OBJECTpublic:Worker() {}virtual ~Worker() {}public slots:void process() {// 輸出當前線程信息qDebug() << "Worker thread running in thread:" << QThread::currentThreadId();// 模擬耗時操作QThread::sleep(3);qDebug() << "Worker process completed.";emit finished();}signals:void finished();
};int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);// 創建線程對象QThread workerThread;Worker worker;// 將 worker 對象移動到新建的線程worker.moveToThread(&workerThread);// 連接信號和槽QObject::connect(&workerThread, &QThread::started, &worker, &Worker::process);QObject::connect(&worker, &Worker::finished, &workerThread, &QThread::quit);QObject::connect(&worker, &Worker::finished, &worker, &Worker::deleteLater);QObject::connect(&workerThread, &QThread::finished, &workerThread, &QThread::deleteLater);// 啟動線程workerThread.start();// 運行事件循環int result = a.exec();// 等待線程結束workerThread.wait();return result;
}#include "main.moc"

運行

Worker thread running in thread: 0x7f1943a36700
Worker process completed.
double free or corruption (out)
15:43:36: The program has unexpectedly finished.

3.2. 代碼二:運行成員函數例程,讓 Worker 類繼承自 QObject,然后使用一個 QThread 實例來在另一個線程中運行這個 Worker 對象

#include <QCoreApplication>
#include <QThread>
#include <QDebug>// Worker類,負責執行實際的計算
class Worker : public QObject {Q_OBJECTpublic:Worker(int a, int b) : m_a(a), m_b(b) {}public slots:void process() {int result = m_a + m_b;  // 簡單的加法計算qDebug() << "計算結果:" << result;emit finished();}signals:void finished();private:int m_a;int m_b;
};int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);int value1 = 5, value2 = 3;Worker *worker = new Worker(value1, value2);QThread *thread = new QThread;// 將worker移動到線程worker->moveToThread(thread);// 連接信號和槽QObject::connect(thread, &QThread::started, worker, &Worker::process);QObject::connect(worker, &Worker::finished, thread, &QThread::quit);QObject::connect(worker, &Worker::finished, worker, &QObject::deleteLater);QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater);QObject::connect(thread, &QThread::finished, &a, &QCoreApplication::quit); // 確保應用退出// 啟動線程thread->start();return a.exec();
}#include "main.moc"

運行

計算結果: 8

四.方法三:直接使用 QThread 和 Lambda

#include <QCoreApplication>
#include <QThread>
#include <QDebug>// 純函數定義,用于計算兩個整數的和
int add(int a, int b) {return a + b;
}int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);// 創建線程對象QThread* thread = new QThread;int x = 3, y = 4;// 將任務移至線程,使用lambda表達式QObject::connect(thread, &QThread::started, [=]() mutable {int result = add(x, y);qDebug() << "The sum of" << x << "and" << y << "is" << result;thread->quit();  // 線程任務完成,請求退出線程});// 清理線程資源QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater);// 啟動線程thread->start();return a.exec();
}

運行

The sum of 3 and 4 is 7

五.方法四:QThread::create(Qt 5.10 及以上)

5.1.提要

  • 直接在 QThread類中沒有提供直接創建并啟動線程執行特定函數的方法(例如 QThread::create 是 C++11 后Qt 5.10 添加的功能,如果您使用的Qt版本較舊,這一功能可能不可用)

  • 在Qt中使用QThread來運行一個全局純函數是一個比較通用的任務,在Qt中,通常通過繼承QThread并重寫run()方法來實現這一點,但使用QThread的能力來直接啟動一個線程執行我們的函數。

5.1.1.QThread::create()代碼一
#include <QCoreApplication>
#include <QThread>
#include <QDebug>void performCalculation(int a, int b) {int result = a + b;qDebug() << "計算結果:" << result;
}int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);QThread *thread = QThread::create(performCalculation, 5, 3);QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater);thread->start();return app.exec();
}
5.1.2.QThread::create()代碼二
#include <QCoreApplication>
#include <QThread>
#include <QDebug>// 全局純函數
void performCalculation(int a, int b) {int result = a + b;  // 簡單的加法計算qDebug() << "計算結果:" << result;
}// 線程執行的函數
void runInThread(int a, int b) {// 創建線程對象QThread* thread = QThread::create([=](){performCalculation(a, b);});// 連接線程結束信號到刪除槽,確保資源被清理QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater);// 啟動線程thread->start();
}int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);// 在線程中執行全局函數runInThread(5, 3);return a.exec();
}

六.方法五:QtConcurrent::run()

#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include <QtConcurrent>// 全局純函數
void performCalculation(int a, int b) {int result = a + b;  // 簡單的加法計算qDebug() << "在線程" << QThread::currentThreadId() << "計算結果:" << result;
}int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);// 使用QtConcurrent運行全局函數int value1 = 5, value2 = 3;QFuture<void> future = QtConcurrent::run(performCalculation, value1, value2);// 等待任務完成future.waitForFinished();return app.exec();
}

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

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

相關文章

ubuntu server 24.04 網絡 SSH等基礎配置

1 安裝參考上一篇: VMware Workstation 虛擬機安裝 ubuntu 24.04 server 詳細教程 服務器安裝圖形化界面-CSDN博客 2 網絡配置 #安裝 sudo apt install net-tools#查看 ifconfig #修改網絡配置 sudo vim /etc/netplan/50-cloud-init.yaml network:version: 2ethernets:en…

課時136:變量進階_變量實踐_高級賦值

2 變量進階 2.1 變量實踐 2.1.1 高級賦值 學習目標 這一節&#xff0c;我們從 基礎知識、簡單實踐、小結 三個方面來學習 基礎知識 簡介 所謂的高級賦值&#xff0c;是另外的一種變量值獲取方法&#xff0c;這里涉及到更多我們學習之外的一些shell內置變量格式,其實這部分…

飛雞:從小訓練飛行的雞能飛行嗎?為什么野雞能飛嗎?是同一品種嗎?今天自由思考

雞的飛行能力在很大程度上受到其生理結構的限制。盡管雞有翅膀&#xff0c;但與能夠長時間飛行的鳥類相比&#xff0c;雞的翅膀相對較小&#xff0c;且胸部肌肉較弱。再加上雞的身體較重&#xff0c;這些因素共同限制了雞的飛行能力。通常&#xff0c;雞只能進行短暫的、低空的…

【wiki知識庫】01.wiki知識庫前后端項目搭建(SpringBoot+Vue3)

&#x1f4dd;個人主頁&#xff1a;哈__ 期待您的關注 &#x1f33c;環境準備 想要搭建自己的wiki知識庫&#xff0c;要提前搭建好自己的開發環境&#xff0c;后端我使用的是SpringBoot&#xff0c;前端使用的是Vue3&#xff0c;采用前后端分離的技術實現。同時使用了Mysql數…

C++ vector,dequeu,list容器中元素的引用失效問題

文章目錄 一、std::list不會產生引用失效問題二、std::vector中元素引用失效問題三、std::deque中元素引用失效問題 一、std::list不會產生引用失效問題 在C中&#xff0c;std::list&#xff08;雙向鏈表&#xff09;提供了一種非常靈活的容器類型&#xff0c;其設計使其在插入…

微信小程序的事件對象屬性,事件綁定

微信小程序 小程序簡介 1 小程序與普通網頁開發的區別&#xff1f; 1運行環境的不同&#xff1a;網頁運行在瀏覽器&#xff0c;小程序運行在微信環境&#xff1b; 2.API 不同&#xff1a;小程序無法調用 DOM 和 BOM 的 API&#xff0c;但可以調用微信環境提供的 API&#xff1…

單工無線發射接收系統

1 緒論 隨著無線電技術的發展,通訊方式也從傳統的有線通訊逐漸轉向無線通訊。由于傳統的有線傳輸系統有配線的問題,較不便利,而無線通訊具有成本廉價、建設工程周期短、適應性好、擴展性好、設備維護容易實現等特點,故未來通訊方式將向無線傳輸系統方向發展。同時,實現系…

mfc140.dll丟失原因和mfc140.dll丟失修復辦法分享

mfc140.dll是與微軟基礎類庫&#xff08;Microsoft Foundation Classes, MFC&#xff09;緊密相關的動態鏈接庫&#xff08;DLL&#xff09;文件。MFC是微軟為C開發者設計的一個應用程序框架&#xff0c;用于簡化Windows應用程序的開發工作。以下是mfc140.dll文件的一些關鍵屬性…

棧的實現(C語言)

文章目錄 前言1.棧的概念及結構2.棧的實現3.具體操作3.1.初始化棧(StackInit)和銷毀棧(StackDestory)3.2.入棧(StackPush)和出棧(StackPop)3.3.獲得棧的個數(StackSize)、獲得棧頂元素(StackTop)以及判空(StackEmpty) 前言 前段時間我們學習過了鏈表和順序表等相關操作&#x…

go-zero 實戰(4)

中間件 在 userapi 項目中引入中間件。go項目中的中間可以處理請求之前和之后的邏輯。 1. 在 userapi/internal目錄先創建 middlewares目錄&#xff0c;并創建 user.go文件 package middlewaresimport ("github.com/zeromicro/go-zero/core/logx""net/http&q…

經濟寒冬下的黃金跳板:方案、活動、競標一手掌握

推薦策劃人必備的寶藏地產策劃資源平臺&#xff0c; 訂閱浩叫&#xff1a;地產營銷策劃圈。這個平臺簡直是地產策劃人的百寶箱&#xff0c;里面藏著無數的策劃秘籍&#xff0c;等著你來挖掘。 這個平臺就像是一個大型的方案庫&#xff0c;里面收錄了眾多知名地產企業的內部資料…

leetcode:計數質數

class Solution { public:// 如果 x 是質數&#xff0c;那么大于 x 的 x 的倍數 2x,3x… 一定不是質數int countPrimes(int n) {vector<int> isPrime(n, 1);int ans 0;for (int i 2; i < n; i) {if (isPrime[i]) {ans 1;if ((long long)i * i < n) {for (int j …

leetcode-55 跳躍游戲

leetcode Problem: 55. 跳躍游戲 思路 假設我們是一個小人&#xff0c;從第一個下標開始&#xff0c;每次經過一個位置&#xff0c;我們就可以根據當前位置的數值nums[i]和位置下標i計算出該位置所能到達的后續位置的最大值rnums[i]i。而這個r之前的區域一定都是可以經過的。…

AI 談“潯川AI翻譯機”

在天工AI&#xff0c;天工AI在全網搜索“潯川AI翻譯機”。 1 創作助手談“潯川AI翻譯機”&#xff1a; “潯川AI翻譯機”是一個利用人工智能技術進行語言翻譯的設備或應用程序。它可以將一種語言的文字或口語翻譯成另一種語言&#xff0c;以實現不同語言之間的溝通和理解。潯…

08. Redis 緩存穿透和雪崩

文章目錄 1. 緩存穿透&#xff08;查不到導致的&#xff09;1.1 概念1.2 解決方案布隆過濾器緩存空對象 2. 緩存擊穿&#xff08;量太大、緩存過期&#xff09;2.1 概念2.2 解決方案設置熱點數據永不過期加互斥鎖 3. 緩存雪崩&#xff08;緩存集體失效或 Redis 宕機&#xff09…

說一下你對dom驅動和數據驅動的理解

DOM驅動和數據驅動是前端開發中兩種常見的操作方式&#xff0c;尤其在構建用戶界面時。下面&#xff0c;我將分別解釋這兩種驅動方式&#xff0c;并提供詳細的代碼示例。 DOM驅動 DOM驅動的核心思想是直接操作DOM元素來更新用戶界面。在早期的Web開發中&#xff0c;這種方式非…

Linux指令初識

ls:顯示當前目錄底下的指定文件或目錄 ls -l更詳細的信息 ls -a顯示當前目錄下的所有文件 命令中的選項可以一次傳遞多個 ,例如&#xff1a;ls -al 命令和選項有必須一個或多個空格 以.開頭的文件&#xff0c;為隱藏文件ls -a可以看到,ls -l看不見 支持命令拼在一起&#…

牛客熱題:滑動窗口的最大值

&#x1f4df;作者主頁&#xff1a;慢熱的陜西人 &#x1f334;專欄鏈接&#xff1a;力扣刷題日記 &#x1f4e3;歡迎各位大佬&#x1f44d;點贊&#x1f525;關注&#x1f693;收藏&#xff0c;&#x1f349;留言 文章目錄 牛客熱題&#xff1a;滑動窗口的最大值題目鏈接方法一…

DNS服務的部署與配置(2)

1、dns的安裝及開啟 dnf install bind.x86_64 -y #安裝 #Berkeley Internet Name Domain (BIND) systemctl enable --now named #啟用dns服務&#xff0c;服務名稱叫named firewall-cmd --permanent --add-servicedns #火墻設置 firewall-cmd --reload …

【手把手搓組件庫】從零開始實現Element Plus--組件開發

從零開始實現Element Plus--組件開發 nvmnvm的作用&#xff1a;nvm的使用方法 需求分析提示詞Kimi 生成產品需求文檔kimi 生成測試用例 初始化 vitest完善 Button 組件1、定義 types.ts2、Button.vue 引入 types.ts3、添加Button樣式點擊事件 添加節流添加 Icon 集成 StoryBook…