91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++中線程的原理與實現方法是什么

發布時間:2023-03-31 17:03:09 來源:億速云 閱讀:130 作者:iii 欄目:開發技術

這篇文章主要介紹“C++中線程的原理與實現方法是什么”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“C++中線程的原理與實現方法是什么”文章能幫助大家解決問題。

在C++中有多種實現線程的方式

  • C++11提供的標準多線程方式;

  • 第三方庫(如:Boost.Thread);

  • 操作系統提供的多線程(如:Windows 線程 與 POSIX 線程(pthread))。

我們這里先了解的就是C++11提供的標準多線程方式。因為它提供了良好的跨平臺兼容性和簡潔的語法,已經滿足大多數需求。

從最簡單的開始

C++11 引入了多線程支持,提供了一套基本的線程庫,包括線程、互斥量(mutex)、條件變量(condition_variable)等。這些組件可以幫助你在 C++ 程序中實現并發和多線程編程。下面是一些基本概念和示例:

1.std::thread:

std::thread 是 C++11 中的線程類,用于創建和管理線程。您可以將一個函數作為參數傳遞給 std::thread 的構造函數,該函數將在新線程中執行。

#include <iostream>
#include <thread>

void hello() {
    std::cout << "Hello from thread!" << std::endl;
}

int main() {
    std::thread t(hello); // 創建一個新線程,執行 hello 函數
    t.join(); // 等待線程結束
    return 0;
}

2.std::mutex:

std::mutex 是互斥量類,用于保護共享資源的訪問。當多個線程需要訪問共享資源時,使用互斥量可以確保每次只有一個線程訪問資源,從而避免數據競爭和其他并發問題。

#include <iostream>
#include <mutex>
#include <thread>

std::mutex mtx; // 互斥量

void print_block(int n, char c) {
    mtx.lock(); // 鎖定互斥量
    for (int i = 0; i < n; ++i) {
        std::cout << c;
    }
    std::cout << std::endl;
    mtx.unlock(); // 解鎖互斥量
}

int main() {
    std::thread t1(print_block, 50, '*');
    std::thread t2(print_block, 50, '$');
    t1.join();
    t2.join();
    return 0;
}

3.std::lock_guard:

std::lock_guard 是一個 RAII(Resource Acquisition Is Initialization)包裝類,用于自動管理互斥量的鎖定和解鎖。當創建 std::lock_guard 對象時,它將自動鎖定互斥量,當對象銷毀時,它將自動解鎖互斥量。

void print_block(int n, char c) {
    std::lock_guard<std::mutex> lock(mtx); // 自動鎖定互斥量
    for (int i = 0; i < n; ++i) {
        std::cout << c;
    }
    std::cout << std::endl;
    // 自動解鎖互斥量(lock_guard 對象銷毀時)
}

4.std::condition_variable:

std::condition_variable 是一個條件變量類,用于在線程之間同步操作。它可以與 std::mutex 配合使用,實現線程間的等待和通知機制。

#include <iostream>
#include <condition_variable>
#include <mutex>
#include <thread>

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void print_id(int id) {
    std::unique_lock<std::mutex> lck(mtx); 
    cv.wait(lck, [] { return ready; }); // 等待 ready 變為 true 
    std::cout << "thread " << id << std::endl; 
} 

void go() { 
    std::unique_lock<std::mutex> lck(mtx);
    ready = true; 
    cv.notify_all();// 通知所有等待的線程 
}

int main() {
    std::thread threads[10];
    for (int i = 0; i < 10; ++i) {
        threads[i] = std::thread(print_id, i); // 啟動 10 個線程 
    }
    
    go(); // 通知所有線程開始執行

    for (auto& th : threads) {
        th.join(); 
    }
    return 0;
}

在這個示例中,我們創建了 10 個線程,每個線程在啟動后等待一個條件變量。主線程通過調用 go 函數將條件變量的狀態設置為 true 并通知所有等待的線程,使它們開始執行。

5.std::future 和 std::async:

std::futurestd::async 是 C++11 提供的用于異步操作的類。std::async 可以異步地執行一個函數,并返回一個 std::future 對象,該對象表示該函數的返回值。您可以通過調用 std::future::get() 來等待函數執行完成并獲取其返回值。

#include <iostream>
#include <future>

int sum(int a, int b) {
    return a + b;
}

int main() {
    std::future<int> result = std::async(sum, 10, 20); // 異步執行 sum 函數
    int value = result.get(); // 等待執行完成并獲取返回值
    std::cout << "The result is: " << value << std::endl;
    return 0;
}

這個簡單的示例展示了如何使用 std::async 異步地執行一個求和函數,然后通過std::future 獲取其結果。

C++11 的多線程支持功能使得在 C++ 中實現并發編程變得更加簡單。通過這些基本組件,您可以根據需要構建更復雜的并發程序。

C++11的線程只有這么簡單嗎?

是也不是。C++11 中的多線程庫確實相對簡單,但這只是表面現象。實際上,它們為復雜的多線程程序提供了基礎。前面已經介紹了一些基本的多線程組件,例如 std::threadstd::mutexstd::condition_variablestd::futurestd::async。但是,還有一些其他的組件和技巧可能會對你有幫助:

1.std::atomic:

C++11 引入了原子類型(std::atomic),用于實現原子操作,即在多線程環境中不會被中斷的操作。原子類型在多線程中特別有用,因為它們可以避免數據競爭和其他并發問題。

示例:

#include <iostream>
#include <atomic>
#include <thread>

std::atomic<int> counter(0);

void increase_counter() {
    for (int i = 0; i < 1000; ++i) {
        ++counter;
    }
}

int main() {
    std::thread t1(increase_counter);
    std::thread t2(increase_counter);

    t1.join();
    t2.join();

    std::cout << "Counter: " << counter << std::endl;
    return 0;
}

2.std::call_once:

std::call_once 是一個用于確保在多線程環境中某個函數只被調用一次的工具。它需要一個 std::once_flag 變量作為參數,該變量用于跟蹤函數是否已被調用。

示例:

#include <iostream>
#include <mutex>
#include <thread>

std::once_flag flag;

void do_something() {
    std::cout << "Called once" << std::endl;
}

void call_do_something() {
    std::call_once(flag, do_something);
}

int main() {
    std::thread t1(call_do_something);
    std::thread t2(call_do_something);

    t1.join();
    t2.join();

    return 0;
}

3.線程局部存儲:

C++11 支持線程局部存儲,即每個線程擁有自己的變量副本。使用 thread_local 關鍵字可以定義一個線程局部變量。這對于某些需要每個線程擁有獨立狀態的應用場景非常有用。

示例:

#include <iostream>
#include <thread>

thread_local int counter = 0;

void increase_counter() {
    ++counter;
    std::cout << "Counter: " << counter << " in thread " << std::this_thread::get_id() << std::endl;
}

int main() {
    std::thread t1(increase_counter);
    std::thread t2(increase_counter);

    t1.join();
    t2.join();

    return 0;
}

以上是 C++11 多線程庫中的一些其他組件和技巧。雖然這些組件相對簡單,但它們為實現復雜的多線程應用提供了基礎。掌握這些基本概念后,你可以根據自己的需求組合這些組件以實現更高級的功能。以下是一些可能對你有幫助的高級用法:

線程池

線程池是一種允許您在一組線程中重用線程以執行任務的技術。這可以減少線程創建和銷毀的開銷,從而提高性能。C++11 沒有提供內置的線程池功能,但您可以使用基本的多線程組件自己實現一個,或者使用第三方庫(例如 Boost.Asio)。

并行算法

C++17 標準引入了并行算法庫,它提供了一些與 STL 算法類似的并行版本,以支持多線程并行執行。這使得實現并行計算變得更加簡單。例如,您可以使用 std::sort 的并行版本 std::execution::par 對大數據集進行排序。

示例:

#include <iostream>
#include <vector>
#include <algorithm>
#include <execution>
#include <random>

int main() {
    std::vector<int> data(100000);
    std::random_device rd;
    std::mt19937 gen(rd());

    std::generate(data.begin(), data.end(), [&]() { return gen() % 1000; });

    std::sort(std::execution::par, data.begin(), data.end());

    // 現在 data 已經被排序
    return 0;
}

lock_guard 和 scoped_lock:

std::lock_guard 是一個簡化互斥鎖管理的 RAII 封裝。當您創建一個 lock_guard 對象時,它將自動鎖定給定的互斥鎖,并在銷毀時自動解鎖。這有助于避免死鎖和忘記解鎖。

std::scoped_lock 是 C++17 引入的一個改進版的 lock_guard,用于同時鎖定多個互斥鎖,避免死鎖。

std::shared_mutex 和 std::shared_lock:

std::shared_mutex 是一種特殊類型的互斥鎖,允許多個線程同時以共享模式訪問資源。std::shared_lock 是與 std::shared_mutex 配合使用的鎖對象,允許您在共享模式或獨占模式下鎖定資源。

以上是 C++11 多線程庫的一些高級用法。熟練掌握這些組件和技巧可以幫助您實現更加高效、可擴展和健壯的多線程應用。

大體其實就這些,另外在設計時還需要注意的是:

避免死鎖:

在多線程編程中,死鎖是一個常見的問題,它發生在兩個或多個線程相互等待對方釋放資源時。為了避免死鎖,請確保使用鎖的順序一致,避免嵌套鎖,并盡量減少鎖的使用范圍。

數據競爭與內存模型:

在多線程環境中,數據競爭是一個潛在的問題。當多個線程同時訪問共享數據且至少有一個線程對數據進行修改時,就會發生數據競爭。避免數據競爭的方法包括使用互斥鎖、原子操作或者線程局部存儲。

此外,C++11 引入了內存模型,用于描述多線程中的內存訪問行為。內存模型包括原子操作的內存順序,例如 std::memory_order_relaxedstd::memory_order_acquirestd::memory_order_release。在大多數情況下,默認的內存順序已經足夠使用,但在某些高級應用場景下,理解和使用內存模型可以幫助您實現更高效的代碼。

性能與可伸縮性:

在編寫多線程程序時,需要權衡性能和可伸縮性。線程之間的通信和同步會導致性能損失,因此您需要在使用更多線程以提高并發性能時,盡量減少同步和通信的開銷。

異常安全:

在多線程環境中,處理異常尤為重要。在一個線程中發生異常時,其他線程可能仍在繼續執行。確保在多線程中正確處理異常,例如使用 try-catch 塊捕獲異常,并確保鎖和資源在異常發生時得到正確的釋放。

第三方庫和框架:

除了 C++ 標準庫提供的多線程支持外,還有一些第三方庫和框架提供了更高級或特定領域的多線程功能。例如,Boost.Thread 庫提供了類似于 C++11 多線程庫的功能,但在某些方面更為強大。Intel 的 Threading Building Blocks (TBB) 是另一個廣泛使用的并行編程庫。

P.S. 再來點與之無關緊要的小知識

join()既然是等待子線程完成,為什么不叫wait_thread()之類的? 而且join本身的單詞是加入,有點感覺格格不入。

因為在多線程編程中,join 方法的命名來源于它的作用:將一個子線程加入(join)到主線程或其他線程,等待這個子線程完成。這種“加入”的概念實際上是指當前線程(通常是主線程)等待另一個線程(子線程)完成它的任務。在子線程完成任務之前,當前線程會阻塞等待。因此,join 這個名字來源于將子線程與等待它的線程連接在一起的過程。簡單來說,當在瘋狂星期四這天的公司樓下KFC里,在你排隊買快樂時,有你的領導插隊(join進來),你必須等它完成的,所以這也就是等待的本意。

wait()

std::condition_variable::wait() 是一個成員函數,用于阻塞當前線程,直到條件變量被通知。wait() 函數通常與 std::unique_lock<std::mutex>std::mutex 配合使用,以便在等待期間自動解鎖互斥量。可以傳遞一個謂詞函數給 wait(),以便在條件變量被通知后檢查是否滿足繼續執行的條件。

notify_all()notify_one

std::condition_variable::notify_all() 是一個成員函數,用于喚醒所有等待當前條件變量的線程。當某個條件滿足時,可以調用 notify_all() 通知所有等待的線程繼續執行。這是一種線程之間協作的方式。

std::condition_variable::notify_one() 也是一個成員函數,用于喚醒一個正在等待該條件變量的線程。與之相對的,notify_all 是喚醒所有正在等待該條件變量的線程。在某些情況下,您可能只需要喚醒一個等待的線程,而不是所有線程,這時候就可以使用 notify_one

再聊聊第三方庫(如:Boost.Thread)方式

#include <iostream>
#include <boost/thread.hpp>

void print_hello() {
    std::cout << "Hello from thread!" << std::endl;
}

int main() {
    boost::thread thread(print_hello);
    thread.join();

    std::cout << "Hello from main!" << std::endl;
    return 0;
}

最后的戰役:操作系統方式

1.POSIX 線程(pthread):

POSIX 線程是基于 POSIX 標準的一種多線程實現,它在類 Unix 系統(如 Linux、macOS)中廣泛使用。pthread 庫提供了用于創建線程、同步、互斥鎖等多線程功能的函數。然而,由于它是用 C 語言編寫的,所以在 C++ 中使用時可能不夠直觀。以下是一個簡單的使用 POSIX 線程的例子:

#include <iostream>
#include <pthread.h>

void* print_hello(void* arg) {
    std::cout << "Hello from thread!" << std::endl;
    return nullptr;
}

int main() {
    pthread_t thread;
    pthread_create(&thread, nullptr, print_hello, nullptr);
    pthread_join(thread, nullptr);

    std::cout << "Hello from main!" << std::endl;
    return 0;
}

2.Windows 線程:

在 Windows 操作系統中,可以通過 Windows API 來創建和管理線程。Windows API 提供了一組用于線程管理、同步和互斥的函數。以下是一個簡單的使用 Windows 線程的例子:

#include <iostream>
#include <windows.h>

DWORD WINAPI print_hello(LPVOID lpParam) {
    std::cout << "Hello from thread!" << std::endl;
    return 0;
}

int main() {
    HANDLE thread = CreateThread(nullptr, 0, print_hello, nullptr, 0, nullptr);
    WaitForSingleObject(thread, INFINITE);
    CloseHandle(thread);

    std::cout << "Hello from main!" << std::endl;
    return 0;
}

關于“C++中線程的原理與實現方法是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

c++
AI

绥宁县| 高要市| 南郑县| 偃师市| 雷州市| 龙口市| 遵化市| 定州市| 柯坪县| 肥城市| 朝阳县| 平罗县| 龙海市| 泽库县| 苍南县| 香格里拉县| 密山市| 远安县| 阳曲县| 罗山县| 泽普县| 房山区| 福州市| 马山县| 堆龙德庆县| 永清县| 曲沃县| 元朗区| 治多县| 南漳县| 建宁县| 开封市| 桐庐县| 阿克| 河源市| 宁陵县| 青浦区| 且末县| 英德市| 宽城| 正镶白旗|