Série: C++
cpp
381 lignes
· Mis à jour 2026-04-03
threads.cpp
C++/Part5_進階主題/Ch23_多執行緒程式設計/threads.cpp
// threads.cpp
// 編譯指令:g++ -std=c++17 -Wall -pthread threads.cpp -o threads
//
// 注意:多執行緒程式必須加上 -pthread 旗標
//
// 本程式示範 std::thread 的基本用法
#include <iostream>
#include <thread>
#include <vector>
#include <string>
#include <functional>
#include <sstream>
#include <mutex>
#include <chrono>
// 全域 mutex 用於同步化主控台輸出
std::mutex cout_mutex;
// 執行緒安全的輸出函式
template<typename... Args>
void safe_print(const Args&... args) {
std::lock_guard<std::mutex> lock(cout_mutex);
(std::cout << ... << args) << "\n";
}
// ============================================================
// 第一部分:基本執行緒建立
// ============================================================
// 一般函式作為執行緒任務
void hello_task() {
safe_print(" [一般函式] Hello from thread! ID: ", std::this_thread::get_id());
}
// 帶參數的函式
void greet(int id, const std::string& name) {
safe_print(" [帶參數] Thread ", id, " says: Hello, ", name, "!");
}
void demo_basic_threads() {
std::cout << "========================================\n";
std::cout << " 基本執行緒建立\n";
std::cout << "========================================\n\n";
// 方式 1:使用一般函式
std::cout << "1. 使用一般函式:\n";
std::thread t1(hello_task);
t1.join();
// 方式 2:使用 lambda
std::cout << "\n2. 使用 lambda:\n";
std::thread t2([]() {
safe_print(" [Lambda] Hello from lambda thread! ID: ",
std::this_thread::get_id());
});
t2.join();
// 方式 3:帶參數的函式
std::cout << "\n3. 帶參數的函式:\n";
std::thread t3(greet, 1, "Alice");
std::thread t4(greet, 2, "Bob");
t3.join();
t4.join();
// 方式 4:帶捕獲的 lambda
std::cout << "\n4. 帶捕獲的 lambda:\n";
int value = 42;
std::thread t5([value]() {
safe_print(" [Lambda 捕獲] 捕獲的值: ", value);
});
t5.join();
std::cout << "\n";
}
// ============================================================
// 第二部分:使用成員函式
// ============================================================
class Worker {
std::string name_;
public:
explicit Worker(const std::string& name) : name_(name) {}
void do_work(int task_id) {
safe_print(" Worker '", name_, "' 正在處理任務 ", task_id);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
safe_print(" Worker '", name_, "' 完成任務 ", task_id);
}
void operator()(int repetitions) {
for (int i = 0; i < repetitions; ++i) {
safe_print(" Worker '", name_, "' 的函式物件呼叫 #", i + 1);
}
}
};
void demo_member_function() {
std::cout << "========================================\n";
std::cout << " 成員函式作為執行緒任務\n";
std::cout << "========================================\n\n";
Worker w1("小明");
Worker w2("小華");
// 傳遞成員函式:需要物件指標
std::cout << "1. 使用成員函式:\n";
std::thread t1(&Worker::do_work, &w1, 101);
std::thread t2(&Worker::do_work, &w2, 102);
t1.join();
t2.join();
// 使用函式物件(operator())
std::cout << "\n2. 使用函式物件:\n";
std::thread t3(Worker("函式物件Worker"), 3);
t3.join();
std::cout << "\n";
}
// ============================================================
// 第三部分:join vs detach
// ============================================================
void demo_join_detach() {
std::cout << "========================================\n";
std::cout << " join vs detach\n";
std::cout << "========================================\n\n";
// join:主執行緒等待子執行緒完成
std::cout << "1. join — 主執行緒等待:\n";
std::thread t1([]() {
safe_print(" 子執行緒開始工作...");
std::this_thread::sleep_for(std::chrono::milliseconds(200));
safe_print(" 子執行緒工作完成!");
});
safe_print(" 主執行緒等待子執行緒...");
t1.join();
safe_print(" 主執行緒確認子執行緒已完成\n");
// detach:子執行緒獨立運行
std::cout << "2. detach — 子執行緒獨立運行:\n";
std::thread t2([]() {
safe_print(" [分離的執行緒] 開始背景工作...");
std::this_thread::sleep_for(std::chrono::milliseconds(50));
safe_print(" [分離的執行緒] 背景工作完成");
});
t2.detach();
safe_print(" 主執行緒不等待,繼續執行");
// 確認 joinable 狀態
std::cout << "\n3. joinable 狀態檢查:\n";
std::thread t3([]() {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
});
safe_print(" 建立後 joinable: ", t3.joinable() ? "是" : "否");
t3.join();
safe_print(" join 後 joinable: ", t3.joinable() ? "是" : "否");
// 給 detached 執行緒一點時間完成
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "\n";
}
// ============================================================
// 第四部分:參數傳遞
// ============================================================
void modify_value(int& value) {
value += 100;
}
void process_string(const std::string& str) {
safe_print(" 處理字串: \"", str, "\" (長度: ", str.size(), ")");
}
void demo_arguments() {
std::cout << "========================================\n";
std::cout << " 執行緒參數傳遞\n";
std::cout << "========================================\n\n";
// 值傳遞(預設行為)
std::cout << "1. 值傳遞(預設):\n";
int x = 42;
std::thread t1([](int val) {
safe_print(" 收到值: ", val);
}, x);
t1.join();
safe_print(" 原始值不變: x = ", x);
// 參考傳遞(需要 std::ref)
std::cout << "\n2. 參考傳遞(std::ref):\n";
int y = 42;
safe_print(" 修改前: y = ", y);
std::thread t2(modify_value, std::ref(y));
t2.join();
safe_print(" 修改後: y = ", y, " (被執行緒修改了)");
// 字串傳遞
std::cout << "\n3. 字串傳遞:\n";
std::string msg = "Hello, Thread!";
std::thread t3(process_string, msg);
t3.join();
// 移動語意
std::cout << "\n4. 移動語意傳遞:\n";
std::string data = "Important Data";
safe_print(" 移動前: data = \"", data, "\"");
std::thread t4([](std::string s) {
safe_print(" 執行緒收到: \"", s, "\"");
}, std::move(data));
t4.join();
safe_print(" 移動後: data = \"", data, "\" (已被移動)");
std::cout << "\n";
}
// ============================================================
// 第五部分:執行緒 ID 與硬體並行度
// ============================================================
void demo_thread_info() {
std::cout << "========================================\n";
std::cout << " 執行緒資訊\n";
std::cout << "========================================\n\n";
// 主執行緒 ID
std::cout << "主執行緒 ID: " << std::this_thread::get_id() << "\n";
// 硬體支援的並行執行緒數
unsigned int hw_threads = std::thread::hardware_concurrency();
std::cout << "硬體並行度: " << hw_threads << " 個執行緒\n\n";
// 各子執行緒回報自己的 ID
std::cout << "子執行緒 ID:\n";
std::vector<std::thread> threads;
for (int i = 0; i < 4; ++i) {
threads.emplace_back([i]() {
safe_print(" Thread ", i, " ID: ", std::this_thread::get_id());
});
}
for (auto& t : threads) {
t.join();
}
std::cout << "\n";
}
// ============================================================
// 第六部分:多執行緒實用範例
// ============================================================
void demo_multiple_threads() {
std::cout << "========================================\n";
std::cout << " 多執行緒實用範例\n";
std::cout << "========================================\n\n";
// 範例 1:平行計算各區段的總和
std::cout << "1. 平行加總:\n";
const int total_elements = 1000;
std::vector<int> data(total_elements);
for (int i = 0; i < total_elements; ++i) data[i] = i + 1;
const int num_threads = 4;
std::vector<long long> partial_sums(num_threads, 0);
std::vector<std::thread> workers;
int chunk_size = total_elements / num_threads;
auto start_time = std::chrono::high_resolution_clock::now();
for (int t = 0; t < num_threads; ++t) {
int begin = t * chunk_size;
int end = (t == num_threads - 1) ? total_elements : begin + chunk_size;
workers.emplace_back([&data, &partial_sums, t, begin, end]() {
long long sum = 0;
for (int i = begin; i < end; ++i) {
sum += data[i];
}
partial_sums[t] = sum;
});
}
for (auto& w : workers) w.join();
long long total_sum = 0;
for (auto s : partial_sums) total_sum += s;
auto end_time = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(
end_time - start_time).count();
long long expected = static_cast<long long>(total_elements) * (total_elements + 1) / 2;
std::cout << " 1 到 " << total_elements << " 的總和 = " << total_sum << "\n";
std::cout << " 預期值 = " << expected << "\n";
std::cout << " 結果" << (total_sum == expected ? "正確" : "錯誤") << "\n";
std::cout << " 使用 " << num_threads << " 個執行緒,耗時 " << duration << " μs\n";
// 範例 2:模擬多個工作者
std::cout << "\n2. 模擬多個工作者:\n";
std::vector<std::thread> task_threads;
std::vector<std::string> task_names = {
"下載檔案", "壓縮資料", "發送郵件", "備份資料庫"
};
for (int i = 0; i < static_cast<int>(task_names.size()); ++i) {
task_threads.emplace_back([i, &task_names]() {
safe_print(" [", task_names[i], "] 開始...");
std::this_thread::sleep_for(
std::chrono::milliseconds(100 + (i * 50)));
safe_print(" [", task_names[i], "] 完成 ✓");
});
}
for (auto& t : task_threads) t.join();
std::cout << " 所有任務完成!\n\n";
}
// ============================================================
// 第七部分:sleep 與 yield
// ============================================================
void demo_sleep_yield() {
std::cout << "========================================\n";
std::cout << " sleep 與 yield\n";
std::cout << "========================================\n\n";
// sleep_for:精確等待
std::cout << "1. sleep_for(精確等待):\n";
auto start = std::chrono::steady_clock::now();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
auto end = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
std::cout << " 要求 sleep 100ms,實際 " << elapsed << "ms\n";
// yield:讓出 CPU 時間片
std::cout << "\n2. yield(讓出 CPU):\n";
std::cout << " yield 提示排程器讓其他執行緒先執行\n";
std::cout << " 通常用在忙等迴圈(busy-wait)中減少 CPU 使用率\n";
// yield 範例:簡單的 spinlock 概念
std::atomic<bool> flag{false};
std::thread setter([&flag]() {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
flag.store(true);
});
int spins = 0;
while (!flag.load()) {
std::this_thread::yield();
++spins;
}
setter.join();
std::cout << " 等待 flag 設定,自旋 " << spins << " 次\n";
std::cout << "\n";
}
// ============================================================
// 主程式
// ============================================================
int main() {
std::cout << "╔══════════════════════════════════════╗\n";
std::cout << "║ C++17 多執行緒:std::thread ║\n";
std::cout << "╚══════════════════════════════════════╝\n\n";
demo_basic_threads();
demo_member_function();
demo_join_detach();
demo_arguments();
demo_thread_info();
demo_multiple_threads();
demo_sleep_yield();
std::cout << "=== 程式結束 ===\n";
return 0;
}
Articles liés
C++
c
Mis à jour 2026-07-21
deviceAlpha.h
deviceAlpha.h — c source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/deviceAlpha.h).
Lire l'article →
C++
c
Mis à jour 2026-07-21
finalproject.c
finalproject.c — c source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/finalproject.c).
Lire l'article →
C++
cpp
Mis à jour 2026-07-21
finalproject.cpp
finalproject.cpp — cpp source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/finalproject.cpp).
Lire l'article →
C++
c
Mis à jour 2026-07-21
deviceAlpha.h
deviceAlpha.h — c source code from the C++ learning materials (C++/Mavis_Homework/Lab8/deviceAlpha.h).
Lire l'article →
C++
c
Mis à jour 2026-07-21
lab8.c
lab8.c — c source code from the C++ learning materials (C++/Mavis_Homework/Lab8/lab8.c).
Lire l'article →
C++
cpp
Mis à jour 2026-07-21
lab8.cpp
lab8.cpp — cpp source code from the C++ learning materials (C++/Mavis_Homework/Lab8/lab8.cpp).
Lire l'article →