c++ 標(biāo)準(zhǔn)庫多線程問題小結(jié)
C++ 多線程編程允許程序同時(shí)執(zhí)行多個(gè)任務(wù),從而提高性能和響應(yīng)能力。C++11 引入了 <thread>
庫,使得多線程編程更加方便。以下是一些基本概念和示例,幫助你理解如何在 C++ 中進(jìn)行多線程編程。
1. 創(chuàng)建線程
使用 std::thread
類可以創(chuàng)建一個(gè)新線程。你需要將一個(gè)函數(shù)或可調(diào)用對(duì)象傳遞給 std::thread
構(gòu)造函數(shù)。
#include <iostream> #include <thread> void threadFunction() { std::cout << "Hello from thread!\\\\n"; } int main() { std::thread t(threadFunction); // 創(chuàng)建線程并執(zhí)行 threadFunction t.join(); // 等待線程結(jié)束 std::cout << "Hello from main!\\\\n"; return 0; }
2. 傳遞參數(shù)給線程函數(shù)
你可以通過 std::thread
構(gòu)造函數(shù)傳遞參數(shù)給線程函數(shù)。
#include <iostream> #include <thread> void printMessage(const std::string& message) { std::cout << message << "\\\\n"; } int main() { std::thread t(printMessage, "Hello from thread!"); t.join(); std::cout << "Hello from main!\\\\n"; return 0; }
3. 線程同步
多個(gè)線程可能會(huì)同時(shí)訪問共享資源,導(dǎo)致數(shù)據(jù)競爭。為了避免這種情況,可以使用互斥鎖(std::mutex
)來保護(hù)共享資源。
#include <iostream> #include <thread> #include <mutex> #include <vector> std::mutex mtx; // 互斥鎖 void printNumber(int num) { mtx.lock(); // 加鎖 std::cout << "Number: " << num << "\\\\n"; mtx.unlock(); // 解鎖 } int main() { std::vector<std::thread> threads; for (int i = 0; i < 10; ++i) { threads.emplace_back(printNumber, i); } for (auto& t : threads) { t.join(); } return 0; }
4. 使用 std::lock_guard 自動(dòng)管理鎖
std::lock_guard
是一個(gè) RAII 風(fēng)格的簡單的鎖管理器,它在構(gòu)造時(shí)自動(dòng)加鎖,在析構(gòu)時(shí)自動(dòng)解鎖。
#include <iostream> #include <thread> #include <mutex> #include <vector> std::mutex mtx; void printNumber(int num) { std::lock_guard<std::mutex> lock(mtx); // 自動(dòng)加鎖和解鎖 std::cout << "Number: " << num << "\\\\n"; } int main() { std::vector<std::thread> threads; for (int i = 0; i < 10; ++i) { threads.emplace_back(printNumber, i); } for (auto& t : threads) { t.join(); } return 0; }
5. 條件變量
條件變量(std::condition_variable
)用于線程間的同步,允許一個(gè)線程等待另一個(gè)線程滿足某些條件。
配合std::condition_variable::wait()
函數(shù)的第一個(gè)參數(shù)的必須是比lock_guard更靈活控制也更復(fù)雜重度的鎖:std::unique_lock。它可以RAII自動(dòng)析構(gòu),也可以手動(dòng)lock/unlock,中間有的代碼段就可以釋放鎖。手動(dòng)把它unlock之后只是解鎖,沒有銷毀,后續(xù)可以按需復(fù)用再次 lock/unlock。
#include <iostream> #include <thread> #include <mutex> #include <condition_variable> std::mutex mtx; std::condition_variable cv; bool ready = false; void printMessage() { std::**unique_lock**<std::mutex> lock(mtx); cv.wait(lock, []{ return ready; }); // 等待條件滿足 std::cout << "Hello from thread!\\\\n"; } int main() { std::thread t(printMessage); { std::lock_guard<std::mutex> lock(mtx); ready = true; // 設(shè)置條件為 true } cv.notify_one(); // 通知等待的線程 t.join(); std::cout << "Hello from main!\\\\n"; return 0; } 相比lock_guard的優(yōu)勢: 1. 靈活性:unique_lock 支持延遲鎖定(可以先構(gòu)造對(duì)象而不立即加鎖),而 lock_guard 在構(gòu)造時(shí)就必須加鎖。這意味著你可以先創(chuàng)建 unique_lock 對(duì)象,然后根據(jù)程序邏輯需要時(shí)再調(diào)用 lock() 或 unlock() 方法進(jìn)行手動(dòng)加鎖或解鎖。 2. 條件變量的支持:unique_lock 可以與標(biāo)準(zhǔn)庫中的條件變量一起使用,如 std::condition_variable,這是 lock_guard 所不具備的功能。這是因?yàn)闂l件變量需要能夠原子地釋放鎖并進(jìn)入等待狀態(tài),這正是 unique_lock 提供的能力之一。 3. 鎖的所有權(quán)轉(zhuǎn)移:unique_lock 支持移動(dòng)語義(move semantics),允許將鎖的所有權(quán)從一個(gè) unique_lock 對(duì)象轉(zhuǎn)移到另一個(gè)對(duì)象,從而使得鎖可以在不同的作用域中傳遞。而 lock_guard 不支持這種操作,它的鎖所有權(quán)是固定的。 4. 嘗試鎖定(try-locking):除了基本的 lock() 和 unlock() 方法外,unique_lock 還提供了 try_lock() 方法,該方法嘗試獲取鎖但不會(huì)阻塞線程,如果無法獲得鎖則立即返回失敗結(jié)果。這對(duì)于避免線程長時(shí)間阻塞非常有用。 wait第二個(gè)參數(shù)predicate謂詞的用法參見: <https://en.cppreference.com/w/cpp/thread/condition_variable/wait> predicate不滿足不會(huì)結(jié)束等待執(zhí)行后續(xù)語句。
6. 線程池
C++ 標(biāo)準(zhǔn)庫沒有直接提供線程池的實(shí)現(xiàn),但你可以使用第三方庫(如 Boost
)或自己實(shí)現(xiàn)一個(gè)簡單的線程池。
#include <iostream> #include <thread> #include <vector> #include <queue> #include <mutex> #include <condition_variable> #include <functional> class ThreadPool { public: ThreadPool(size_t numThreads) { for (size_t i = 0; i < numThreads; ++i) { workers.emplace_back([this] { while (true) { std::function<void()> task; { std::unique_lock<std::mutex> lock(this->queueMutex); this->condition.wait(lock, [this] { return this->stop || !this->tasks.empty(); }); if (this->stop && this->tasks.empty()) return; task = std::move(this->tasks.front()); this->tasks.pop(); } task(); } }); } } template<class F> void enqueue(F&& f) { { std::unique_lock<std::mutex> lock(queueMutex); tasks.emplace(std::forward<F>(f)); } condition.notify_one(); } ~ThreadPool() { { std::unique_lock<std::mutex> lock(queueMutex); stop = true; } condition.notify_all(); for (std::thread &worker : workers) { worker.join(); } } private: std::vector<std::thread> workers; std::queue<std::function<void()>> tasks; std::mutex queueMutex; std::condition_variable condition; bool stop = false; }; int main() { ThreadPool pool(4); for (int i = 0; i < 8; ++i) { pool.enqueue([i] { std::cout << "Task " << i << " is running on thread " << std::this_thread::get_id() << "\\\\n"; }); } return 0; }
7. 線程局部存儲(chǔ)
線程局部存儲(chǔ)(Thread Local Storage, TLS)允許每個(gè)線程擁有自己的變量實(shí)例。C++11 引入了 thread_local
關(guān)鍵字來實(shí)現(xiàn)這一點(diǎn)。
#include <iostream> #include <thread> thread_local int threadLocalVar = 0; void threadFunction(int id) { threadLocalVar = id; std::cout << "Thread " << id << " has threadLocalVar = " << threadLocalVar << "\\\\n"; } int main() { std::thread t1(threadFunction, 1); std::thread t2(threadFunction, 2); t1.join(); t2.join(); return 0; }
8. 異步任務(wù)
C++11 還引入了 std::async
和 std::future
,用于異步執(zhí)行任務(wù)并獲取結(jié)果。
#include <iostream> #include <future> int compute() { std::this_thread::sleep_for(std::chrono::seconds(2)); return 42; } int main() { // 啟動(dòng)異步任務(wù) std::future<int> fut = std::async(std::launch::async, compute); // 獲取結(jié)果 int result = fut.get(); std::cout << "Result: " << result << std::endl; return 0; } //使用 std::packaged_task (包在線程函數(shù)外)------------------------------------------ #include <iostream> #include <future> #include <thread> int compute() { std::this_thread::sleep_for(std::chrono::seconds(2)); return 42; } int main() { // 創(chuàng)建 packaged_task std::packaged_task<int()> task(compute); // 獲取 future std::future<int> fut = task.get_future(); // 在另一個(gè)線程中執(zhí)行任務(wù) std::thread t(std::move(task)); t.join(); // 獲取結(jié)果 int result = fut.get(); std::cout << "Result: " << result << std::endl; return 0; } // 使用 std::promise (作為線程函數(shù)參數(shù)) ----------------------------------------------- #include <iostream> #include <future> #include <thread> void compute(std::promise<int> prom) { std::this_thread::sleep_for(std::chrono::seconds(2)); prom.set_value(42); } int main() { // 創(chuàng)建 promise 和 future std::promise<int> prom; std::future<int> fut = prom.get_future(); // 在另一個(gè)線程中執(zhí)行任務(wù) std::thread t(compute, std::move(prom)); // 獲取結(jié)果 int result = fut.get(); std::cout << "Result: " << result << std::endl; t.join(); return 0; }
異步機(jī)制總結(jié): C++11 的異步機(jī)制(std::future、std::async、std::packaged_task 和 std::promise)相比傳統(tǒng)的多線程編程,提供了以下額外的好處:
更高的抽象層次,簡化了異步操作的管理。
自動(dòng)化的結(jié)果傳遞和異常處理。
更靈活的線程管理和任務(wù)執(zhí)行策略。
更清晰的代碼結(jié)構(gòu)和更低的耦合度。
支持任務(wù)組合和超時(shí)等待。
這些機(jī)制使異步編程更加直觀、安全和高效,是現(xiàn)代 C++ 并發(fā)編程的重要組成部分。
總結(jié)
C++ 多線程編程提供了強(qiáng)大的工具來處理并發(fā)任務(wù)。通過使用 std::thread
、std::mutex
、std::condition_variable
等工具,你可以編寫高效且安全的多線程程序。需要注意的是,多線程編程容易引入數(shù)據(jù)競爭和死鎖等問題,因此需要仔細(xì)設(shè)計(jì)和測試。
到此這篇關(guān)于c++ 標(biāo)準(zhǔn)庫多線程的文章就介紹到這了,更多相關(guān)c++ 標(biāo)準(zhǔn)庫多線程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- c++標(biāo)準(zhǔn)庫讀寫ini文件的實(shí)現(xiàn)示例
- C++標(biāo)準(zhǔn)庫介紹及使用string類的詳細(xì)過程
- C++11標(biāo)準(zhǔn)庫 互斥鎖 <mutex> 詳解
- 詳解C++標(biāo)準(zhǔn)庫中處理正則表達(dá)式的類std::regex
- C++標(biāo)準(zhǔn)庫學(xué)習(xí)之weak_ptr智能指針用法詳解
- 常用的C++標(biāo)準(zhǔn)庫頭文件小結(jié)
- C++超詳細(xì)講解標(biāo)準(zhǔn)庫
- C++ STL標(biāo)準(zhǔn)庫std::vector的使用詳解
- C++ vector在多線程操作中出現(xiàn)內(nèi)存錯(cuò)誤問題及解決
- C++多線程中互斥量的使用詳解
相關(guān)文章
c++函數(shù)中的指針參數(shù)與地址參數(shù)區(qū)別介紹
c++函數(shù)中的指針參數(shù)與地址參數(shù)區(qū)別介紹;可供參考2012-11-11Dashboard Interface 應(yīng)用實(shí)現(xiàn)操作
Dashboard Server Remote Control Interface是一個(gè)關(guān)鍵的功能,它為用戶提供了通過TCP/IP協(xié)議遠(yuǎn)程控制機(jī)器人的能力,執(zhí)行包括開關(guān)機(jī)、加載程序、檢查機(jī)器人狀態(tài)以及設(shè)置機(jī)器人操作模式等多種操作,本文介紹Dashboard Interface 應(yīng)用操作,感興趣的朋友跟隨小編一起看看吧2024-08-08