C++ 多線程:初學者指南
你好,未來的編程超級巨星!很高興能成為你在這個令人興奮的C++多線程世界之旅的導遊。作為一個教編程多年的老師,我可以向您保證,這個主題一開始可能會讓人感到畏難,但一旦您掌握了它,其實非常吸引人。所以,讓我們捲起袖子,深入探險吧!
什麼是多線程?
在我們深入細節之前,先從基礎開始。想象一下您正在廚房裡,試圖準備一頓複雜的飯菜。您可以一步一步地做——先切蔬菜,然後煮義大利麵,然後準備醬汁。但如果是同時進行這些工作,不是更有效率嗎?這基本上就是多線程在我們的程序中所做的事情!
多線程允許程序同時執行多個任務。每個任務都被稱為一個“線程”。這就像廚房中有多位廚師,每個人負責飯菜的不同部分。
現在,讓我們看看如何在C++中利用這種力量!
創建線程
在C++中創建線程就像為我們的廚房聘請一位新的廚師。我們需要告訴這位廚師(線程)要執行哪項任務。在C++中,我們使用<thread>
庫中的std::thread
類來做到這一點。
來看看一個簡單的例子:
#include <iostream>
#include <thread>
void cookPasta() {
std::cout << "Cooking pasta..." << std::endl;
}
int main() {
std::thread chefOne(cookPasta);
chefOne.join();
return 0;
}
在這個例子中:
- 我們包含了必要的庫:
<iostream>
用於輸入/輸出,<thread>
用於多線程。 - 我們定義了一個函數
cookPasta()
,我們的線程將執行它。 - 在
main()
中,我們創建了一個名為chefOne
的線程,並告訴它執行cookPasta()
函數。 - 我們使用
join()
在程序結束之前等待線程完成其任務。
當您運行此程序時,您將會在控制台上看到“Cooking pasta...”的輸出。恭喜!您剛剛創建了您的第一個線程!
結束線程
現在,如果我們的廚師煮義大利麵花費的時間太長怎麼辦?在編程的世界中,我們可能需要在線程完成其任務之前終止它。但是,重要的是要注意,強行終止線程可能會導致資源洩露和其他問題。通常更好的做法是設計線程自然完成或響應終止信號。
以下是一個如何設置線程以響應終止信號的例子:
#include <iostream>
#include <thread>
#include <atomic>
std::atomic<bool> stop_thread(false);
void cookPasta() {
while (!stop_thread) {
std::cout << "Still cooking pasta..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
std::cout << "Pasta cooking stopped!" << std::endl;
}
int main() {
std::thread chefOne(cookPasta);
std::this_thread::sleep_for(std::chrono::seconds(5));
stop_thread = true;
chefOne.join();
return 0;
}
在這個例子中:
- 我們使用一個
atomic<bool>
變量stop_thread
來在線程之間安全地通信。 - 我們的
cookPasta()
函數現在在循環中檢查這個變量。 - 在
main()
中,我們讓線程運行5秒鐘,然後將stop_thread
設為true。 - 線程響應結束其循環並自然結束。
向線程傳遞參數
如果我們想給我們的廚師更具體的指示怎麼辦?在C++中,我們可以像傳遞函數參數一樣將參數傳遞給我們的線程。讓我們看看如何操作:
#include <iostream>
#include <thread>
#include <string>
void cookDish(std::string dish, int time) {
std::cout << "Cooking " << dish << " for " << time << " minutes." << std::endl;
}
int main() {
std::thread chefOne(cookDish, "Spaghetti", 10);
std::thread chefTwo(cookDish, "Pizza", 15);
chefOne.join();
chefTwo.join();
return 0;
}
在這個例子中:
- 我們的
cookDish()
函數現在需要兩個參數:菜名和烹飪時間。 - 我們創建了兩個線程,每個線程烹飪不同的菜,時間也不同。
- 我們在創建線程時直接傳遞這些參數。
這展示了線程可以有多麼靈活——我們可以有多個線程執行類似的任務,但參數不同!
加入和分离線程
最後,讓我們談談兩個重要的概念:加入和分離線程。
加入線程
我們在前面的例子中已經看到了join()
。當我們在線程上調用join()
時,我們是告訴主程序在繼續之前等待該線程完成。這就像等待廚師準備好一道菜再上菜一樣。
分離線程
有時,我們可能希望線程獨立運行,而不等待它完成。這就是detach()
的用處。一個分離的線程會在背景中繼續運行,即使主程序結束了。
以下是一個說明兩者的例子:
#include <iostream>
#include <thread>
#include <chrono>
void slowCook(std::string dish) {
std::this_thread::sleep_for(std::chrono::seconds(3));
std::cout << dish << " is ready!" << std::endl;
}
void quickCook(std::string dish) {
std::cout << dish << " is ready!" << std::endl;
}
int main() {
std::thread slowChef(slowCook, "Stew");
std::thread quickChef(quickCook, "Salad");
slowChef.detach(); // 讓慢廚師在背景工作
quickChef.join(); // 等待快廚師完成
std::cout << "Main program ending. Slow chef might still be working!" << std::endl;
return 0;
}
在這個例子中:
- 我們有兩位廚師:一位慢慢烹飪炖菜,一位快速準備沙拉。
- 我們分離了慢廚師的線程,讓它可以在背景中繼續工作。
- 我們加入快廚師的線程,等待沙拉準備好。
- 主程序結束,可能會在炖菜準備好之前。
方法 | 描述 | 使用情況 |
---|---|---|
join() | 等待線程完成 | 當您需要在繼續之前獲得線程的結果時 |
detach() | 允許線程獨立運行 | 對於可以獨立運行的背景任務 |
就是這樣,各位!您剛剛踏出了C++多線程世界的第一步。請記住,就像學習烹飪一樣,掌握多線程需要練習。不要害怕嘗試這些概念,很快您就能夠像廚房中的大廚一樣,輕鬆地編織出複雜、高效的程序!
編程愉快,願您的線程永遠運行平順!
Credits: Image by storyset