C++系列十:日常學習-多線程

来源:https://www.cnblogs.com/zhouyitty/archive/2023/09/06/17681691.html
-Advertisement-
Play Games

[TOC](多線程) # 介紹: C++ 是一種支持多線程編程的編程語言,它提供了豐富的多線程支持來充分利用現代多核處理器的性能。 C++ 多線程編程通常使用標準庫中的 頭文件以及其他相關的標準庫組件來實現。 # 理論: 1. 常用的類: std::thread 類,用於創建和管理線程等等 std: ...


目錄

介紹:

C++ 是一種支持多線程編程的編程語言,它提供了豐富的多線程支持來充分利用現代多核處理器的性能。
C++ 多線程編程通常使用標準庫中的 頭文件以及其他相關的標準庫組件來實現。

理論:

  1. 常用的類:
    std::thread 類,用於創建和管理線程等等
    std::this_thread 命名空間中的函數來處理線程的等待和分離等等
    互斥鎖(std::mutex)、條件變數(std::condition_variable)和原子操作(std::atomic)

  2. 線程池:
    線程池是一種管理和復用線程的技術,以避免頻繁創建和銷毀線程。C++ 標準庫中沒有直接提供線程池的實現,但你可以使用第三方庫或自己編寫一個簡單的線程池。

  3. 請註意,多線程編程可能會引入一些複雜性和潛在的問題,如競態條件和死鎖。因此,確保充分理解多線程編程的概念和最佳實踐,並使用適當的同步機制來確保線程安全是非常重要的。

案例:

std::thread:
join() //阻塞當前線程,直到目標線程執行完畢。
detach() //將線程分離,使其成為後臺線程,不再受到 join() 的控制。


//創建互斥鎖,併在訪問共用資源之前進行鎖定。
std::mutex mtx;
mtx.lock();   // 鎖定互斥鎖
// 訪問共用資源
mtx.unlock(); // 解鎖互斥鎖


//自動管理鎖的生命周期,以確保在離開作用域時自動釋放鎖。
std::mutex mtx;
{
    std::lock_guard<std::mutex> lock(mtx); // 自動鎖定和解鎖
    // 訪問共用資源
} // 離開作用域時自動解鎖


//條件變數用於線上程之間進行通信和同步。它們允許一個線程等待另一個線程發出的通知,以執行某些操作。
std::condition_variable cv;
// 線程1等待通知
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock); // 阻塞線程1,直到收到通知
// 線程2發送通知
cv.notify_one(); // 通知線程1


//原子操作:
std::atomic<int> counter(0);
counter.fetch_add(1, std::memory_order_relaxed); // 原子遞增操作


//案例1:
#include <iostream>
#include <thread>

void myFunction() {
    // 線程1執行的代碼
}
void myFunction1(int value) {
    // 線程2執行的代碼
}

int main() {
    std::thread t1(myFunction); // 創建新線程並啟動
    std::thread t2(myFunction1,100); // 創建新線程並啟動
    t1.join(); // 等待線程完成
    t2.join(); // 等待線程完成
    return 0;
}

//案例2:
#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;

void myFunction(int& counter) {
    for (int i = 0; i < 1000; ++i) {
        std::lock_guard<std::mutex> lock(mtx); // 使用互斥鎖保護共用資源
        counter++;
    }
}

int main() {
    int counter = 0;
    std::thread t1(myFunction, std::ref(counter));
    std::thread t2(myFunction, std::ref(counter));
    t1.join();
    t2.join();
    std::cout << "Counter: " << counter << std::endl;//Counter: 2000
    return 0;
}


生產者-消費者問題:

這就有意思多了,多看多吸收,多悟
不理解得就多問問Chatjpt。

//一對一:
#include <iostream>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>

std::queue<int> buffer;
std::mutex mtx;
std::condition_variable cv;

void producer() {
    for (int i = 0; i < 10; ++i) {
        std::this_thread::sleep_for(std::chrono::milliseconds(200));

        // 鎖定互斥鎖以保護共用資源
        {
            std::lock_guard<std::mutex> lock(mtx);
            buffer.push(i);
            std::cout << "Produced: " << i << std::endl;
        }

        // 通知消費者線程有新數據可用
        cv.notify_one();
    }
}

void consumer() {
    for (int i = 0; i < 10; ++i) {
        // 鎖定互斥鎖,等待條件變數通知
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, []{ return !buffer.empty(); });

        // 消費數據
        int data = buffer.front();
        buffer.pop();

        // 解鎖互斥鎖
        lock.unlock();

        std::cout << "Consumed: " << data << std::endl;
    }
}

int main() {
    std::thread producerThread(producer);
    std::thread consumerThread(consumer);

    producerThread.join();
    consumerThread.join();

    return 0;
}

//一對多:
#include <iostream>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <vector>

std::queue<int> buffer;
std::mutex mtx;
std::condition_variable cv;
const int numProducers = 3; // 多個生產者線程

void producer(int id) {
    for (int i = 0; i < 5; ++i) {
        std::this_thread::sleep_for(std::chrono::milliseconds(200));

        {
            std::lock_guard<std::mutex> lock(mtx);
            int data = id * 100 + i;
            buffer.push(data);
            std::cout << "Producer " << id << " produced: " << data << std::endl;
        }

        cv.notify_one();
    }
}

void consumer() {
    for (int i = 0; i < 15; ++i) { // 總共消費 15 個數據項
        std::unique_lock<std::mutex> lock(mtx);

        cv.wait(lock, []{ return !buffer.empty(); }); // 等待緩衝區非空

        int data = buffer.front();
        buffer.pop();

        lock.unlock();

        std::cout << "Consumer consumed: " << data << std::endl;
    }
}

int main() {
    std::vector<std::thread> producerThreads;

    for (int i = 0; i < numProducers; ++i) {
        producerThreads.push_back(std::thread(producer, i));
    }

    std::thread consumerThread(consumer);

    for (std::thread& thread : producerThreads) {
        thread.join();
    }
    consumerThread.join();

    return 0;
}


//多對多
#include <iostream>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <vector>

std::queue<int> buffer; // 緩衝區隊列
std::mutex mtx; // 互斥鎖,用於保護共用資源
std::condition_variable cv; // 條件變數,用於線程間通信

const int numProducers = 2; // 多個生產者線程
const int numConsumers = 2; // 多個消費者線程
const int bufferSize = 10; // 緩衝區大小

void producer(int id) {
    for (int i = 0; i < 5; ++i) { // 生產者每個生成 5 個數據項
        std::this_thread::sleep_for(std::chrono::milliseconds(200));

        {
            std::unique_lock<std::mutex> lock(mtx);

            // 等待緩衝區有空間可用
            cv.wait(lock, []{ return buffer.size() < bufferSize; });

            int data = id * 100 + i;
            buffer.push(data);
            std::cout << "Producer " << id << " produced: " << data << std::endl;
        }

        cv.notify_all(); // 通知所有等待的線程
    }
}

void consumer(int id) {
    for (int i = 0; i < 5; ++i) { // 消費者每個消費 5 個數據項
        std::this_thread::sleep_for(std::chrono::milliseconds(200));

        {
            std::unique_lock<std::mutex> lock(mtx);

            // 等待緩衝區非空
            cv.wait(lock, []{ return !buffer.empty(); });

            int data = buffer.front();
            buffer.pop();

            lock.unlock(); // 解鎖互斥鎖,允許其他線程進入臨界區

            std::cout << "Consumer " << id << " consumed: " << data << std::endl;
        }

        cv.notify_all(); // 通知所有等待的線程
    }
}

int main() {
    std::vector<std::thread> producerThreads;
    std::vector<std::thread> consumerThreads;

    for (int i = 0; i < numProducers; ++i) {
        // 創建生產者線程,並傳遞唯一的標識符 i
        producerThreads.push_back(std::thread(producer, i));
    }

    for (int i = 0; i < numConsumers; ++i) {
        // 創建消費者線程,並傳遞唯一的標識符 i
        consumerThreads.push_back(std::thread(consumer, i));
    }

    for (std::thread& thread : producerThreads) {
        thread.join(); // 等待生產者線程結束
    }

    for (std::thread& thread : consumerThreads) {
        thread.join(); // 等待消費者線程結束
    }

    return 0;
}



您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • for迴圈用於多次執行特定的代碼塊,每次都可以使用不同的值。每次迴圈執行都稱為一次迭代。for迴圈可以包含最多三個語句: 語法 ```Go for 語句1; 語句2; 語句3 { // 每次迭代要執行的代碼 } ``` - 語句1:初始化迴圈計數器的值。 - 語句2:對每次迴圈迭代進行評估。如果評估 ...
  • ## Synchronized 本篇文章將圍繞synchronized關鍵字,使用大量圖片、案例深入淺出的描述CAS、synchronized Java層面和C++層面的實現、鎖升級的原理、源碼等 大概觀看時間17分鐘 可以帶著幾個問題去查看本文,如果認真看完,問題都會迎刃而解: 1、synchro ...
  • 小魚和魔法師繼續深入魔法森林。不久,他們來到了一個巨大的魔法石圈旁邊。石圈中心有一個閃閃發光的魔法水晶,周圍則是一些神秘的符號。但令人意外的是,水晶的旁邊還有一個巨大的石像怪,它的眼睛散髮著紅色的光芒,似乎正在守護著這片區域。 小魚好奇地問:“這是什麼地方?這些符號又是什麼意思?那個石像怪又是怎麼回 ...
  • 大家好,我是棧長。 昨天有粉絲反饋棧長《[Spring Boot 核心技術課](https://mp.weixin.qq.com/s/hJwHvmalVWJObyVkytfdsA)》中的一個問題: ![](https://img2023.cnblogs.com/other/1218593/20230 ...
  • 最近又是一輪代碼review , 發現了一些實現去重的代碼,在使用 list.contain ...... ![](https://img2023.cnblogs.com/other/1218593/202309/1218593-20230906151256318-1035375358.png) 我 ...
  • 在日常開發中,當需要給一個現有類添加附加職責,而又不能採用生成子類的方法進行擴充時。例如,該類被隱藏或者該類是終極類或者採用繼承方式會產生大量的子類。這時候,我們該怎麼辦呢?我們可以使用裝飾器器模式來解決這個問題,**本文將從以下四個方面講解裝飾器器模式**。 - 簡介 - 優缺點 - 應用場景 - ...
  • 掩碼是一串二進位代碼對目標欄位進行位與運算 # 掩碼 掩碼通常是一個用於屏蔽或隱藏某些位的值,以便在計算中只關註感興趣的位。掩碼通常是一個由二進位位組成的數,用於按位與操作,以清除或保留某些位的值。 常見的用途包括: 1. **位操作和位掩碼**:在電腦編程中,位掩碼用於執行位操作,如按位與(AN ...
  • > 關註TechLeadCloud,分享互聯網架構、雲服務技術的全維度知識。作者擁有10+年互聯網服務架構、AI產品研發經驗、團隊管理經驗,同濟本復旦碩,復旦機器人智能實驗室成員,阿裡雲認證的資深架構師,項目管理專業人士,上億營收AI產品研發負責人。 ![file](https://img2023. ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...