Serie: C++
cpp
542 righe
· Aggiornato 2026-04-03
async_future.cpp
C++/Part5_進階主題/Ch23_多執行緒程式設計/async_future.cpp
// async_future.cpp
// 編譯指令:g++ -std=c++17 -Wall -pthread async_future.cpp -o async_future
//
// 注意:多執行緒程式必須加上 -pthread 旗標
//
// 本程式示範 std::async、std::future、std::promise、std::shared_future
#include <iostream>
#include <future>
#include <thread>
#include <vector>
#include <string>
#include <numeric>
#include <chrono>
#include <cmath>
#include <stdexcept>
#include <mutex>
#include <sstream>
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";
}
// ============================================================
// 第一部分:std::async 基本用法
// ============================================================
// 模擬耗時計算
long long compute_sum(int start, int end) {
long long sum = 0;
for (int i = start; i <= end; ++i) {
sum += i;
}
return sum;
}
// 模擬下載檔案
std::string download_file(const std::string& url) {
safe_print(" 下載中: ", url);
std::this_thread::sleep_for(std::chrono::milliseconds(200));
return "內容來自 " + url;
}
void demo_async_basics() {
std::cout << "========================================\n";
std::cout << " std::async 基本用法\n";
std::cout << "========================================\n\n";
// 基本 async 呼叫
std::cout << "1. 基本非同步呼叫:\n";
auto future1 = std::async(std::launch::async, compute_sum, 1, 1000000);
std::cout << " 計算已在背景啟動...\n";
std::cout << " 主執行緒可以做其他事情...\n";
long long result = future1.get(); // 阻塞直到結果就緒
std::cout << " 1 到 1000000 的總和 = " << result << "\n";
// 使用 lambda
std::cout << "\n2. 使用 lambda:\n";
auto future2 = std::async(std::launch::async, []() {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
return 42;
});
std::cout << " 等待結果: " << future2.get() << "\n";
// 多個非同步任務
std::cout << "\n3. 多個非同步任務(模擬平行下載):\n";
auto start = std::chrono::steady_clock::now();
auto f1 = std::async(std::launch::async, download_file, "file1.txt");
auto f2 = std::async(std::launch::async, download_file, "file2.txt");
auto f3 = std::async(std::launch::async, download_file, "file3.txt");
std::cout << " " << f1.get() << "\n";
std::cout << " " << f2.get() << "\n";
std::cout << " " << f3.get() << "\n";
auto end = std::chrono::steady_clock::now();
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
std::cout << " 三個下載共耗時 " << ms << " ms(平行執行,非 3x200ms)\n\n";
}
// ============================================================
// 第二部分:啟動策略
// ============================================================
void demo_launch_policies() {
std::cout << "========================================\n";
std::cout << " 啟動策略(launch policies)\n";
std::cout << "========================================\n\n";
// std::launch::async — 保證在新執行緒執行
std::cout << "1. std::launch::async(在新執行緒執行):\n";
auto f1 = std::async(std::launch::async, []() {
safe_print(" [async] 執行緒 ID: ", std::this_thread::get_id());
return 100;
});
std::cout << " 主執行緒 ID: " << std::this_thread::get_id() << "\n";
std::cout << " 結果: " << f1.get() << "\n";
// std::launch::deferred — 延遲到 get() 時在呼叫者執行緒執行
std::cout << "\n2. std::launch::deferred(延遲執行):\n";
auto f2 = std::async(std::launch::deferred, []() {
safe_print(" [deferred] 執行緒 ID: ", std::this_thread::get_id());
return 200;
});
std::cout << " 呼叫 get() 前,函式尚未執行\n";
std::cout << " 主執行緒 ID: " << std::this_thread::get_id() << "\n";
std::cout << " 結果: " << f2.get() << " (此時才執行)\n";
// 預設策略
std::cout << "\n3. 預設策略(async | deferred):\n";
auto f3 = std::async([]() {
return 300;
});
std::cout << " 由系統決定在新執行緒或延遲執行\n";
std::cout << " 結果: " << f3.get() << "\n\n";
}
// ============================================================
// 第三部分:future 的操作
// ============================================================
void demo_future_operations() {
std::cout << "========================================\n";
std::cout << " std::future 操作\n";
std::cout << "========================================\n\n";
// valid() — 檢查 future 是否有效
std::cout << "1. valid() 檢查:\n";
std::future<int> f1;
std::cout << " 預設建構的 future valid: " << std::boolalpha << f1.valid() << "\n";
f1 = std::async(std::launch::async, []() { return 42; });
std::cout << " 設定後 valid: " << f1.valid() << "\n";
f1.get();
std::cout << " get() 後 valid: " << f1.valid() << "\n";
// wait() — 等待但不取值
std::cout << "\n2. wait() 等待:\n";
auto f2 = std::async(std::launch::async, []() {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
return 99;
});
std::cout << " 等待完成...\n";
f2.wait();
std::cout << " 已完成,取值: " << f2.get() << "\n";
// wait_for() — 限時等待
std::cout << "\n3. wait_for() 限時等待:\n";
auto f3 = std::async(std::launch::async, []() {
std::this_thread::sleep_for(std::chrono::milliseconds(300));
return 77;
});
auto status = f3.wait_for(std::chrono::milliseconds(50));
if (status == std::future_status::timeout) {
std::cout << " 50ms 後:超時(尚未完成)\n";
} else if (status == std::future_status::ready) {
std::cout << " 50ms 後:已就緒\n";
}
// 繼續等待直到完成
status = f3.wait_for(std::chrono::milliseconds(500));
if (status == std::future_status::ready) {
std::cout << " 再等 500ms 後:已就緒,值 = " << f3.get() << "\n";
}
// future_status 的所有值
std::cout << "\n4. future_status 列舉:\n";
std::cout << " ready - 結果已就緒\n";
std::cout << " timeout - 等待逾時\n";
std::cout << " deferred - 使用 deferred 策略且尚未開始\n";
std::cout << "\n";
}
// ============================================================
// 第四部分:std::promise 與 std::future 配對
// ============================================================
void demo_promise_future() {
std::cout << "========================================\n";
std::cout << " std::promise 與 std::future\n";
std::cout << "========================================\n\n";
// 基本使用:在執行緒間傳遞值
std::cout << "1. 基本值傳遞:\n";
{
std::promise<int> promise;
std::future<int> future = promise.get_future();
std::thread t([&promise]() {
safe_print(" [工作者] 計算中...");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
promise.set_value(42);
safe_print(" [工作者] 已設定結果");
});
std::cout << " [主程式] 等待結果...\n";
int result = future.get();
std::cout << " [主程式] 收到: " << result << "\n";
t.join();
}
// 傳遞字串
std::cout << "\n2. 傳遞複雜型別:\n";
{
std::promise<std::string> promise;
auto future = promise.get_future();
std::thread t([&promise]() {
std::string result = "計算結果: ";
for (int i = 0; i < 5; ++i) {
result += std::to_string(i * i) + " ";
}
promise.set_value(std::move(result));
});
std::cout << " 收到: \"" << future.get() << "\"\n";
t.join();
}
// 傳遞例外
std::cout << "\n3. 傳遞例外:\n";
{
std::promise<double> promise;
auto future = promise.get_future();
std::thread t([&promise]() {
try {
// 模擬錯誤
throw std::runtime_error("除以零錯誤");
} catch (...) {
promise.set_exception(std::current_exception());
}
});
try {
double result = future.get();
std::cout << " 結果: " << result << "\n";
} catch (const std::exception& e) {
std::cout << " 捕獲例外: " << e.what() << "\n";
}
t.join();
}
// 多階段流水線
std::cout << "\n4. 多階段流水線:\n";
{
std::promise<int> p1, p2, p3;
auto f1 = p1.get_future();
auto f2 = p2.get_future();
auto f3 = p3.get_future();
// 階段 1:產生資料
std::thread stage1([&p1]() {
safe_print(" [階段1] 產生資料...");
std::this_thread::sleep_for(std::chrono::milliseconds(50));
p1.set_value(10);
});
// 階段 2:處理資料
std::thread stage2([&f1, &p2]() {
int input = f1.get();
safe_print(" [階段2] 收到 ", input, ",處理中...");
std::this_thread::sleep_for(std::chrono::milliseconds(50));
p2.set_value(input * 3);
});
// 階段 3:最終處理
std::thread stage3([&f2, &p3]() {
int input = f2.get();
safe_print(" [階段3] 收到 ", input, ",最終處理...");
std::this_thread::sleep_for(std::chrono::milliseconds(50));
p3.set_value(input + 7);
});
int final_result = f3.get();
std::cout << " 最終結果: " << final_result << " (10 * 3 + 7 = 37)\n";
stage1.join();
stage2.join();
stage3.join();
}
std::cout << "\n";
}
// ============================================================
// 第五部分:std::shared_future
// ============================================================
void demo_shared_future() {
std::cout << "========================================\n";
std::cout << " std::shared_future(多個消費者)\n";
std::cout << "========================================\n\n";
// shared_future 可以被多次 get(),多個執行緒共用
std::promise<int> promise;
std::shared_future<int> shared = promise.get_future().share();
std::vector<std::thread> consumers;
for (int i = 0; i < 4; ++i) {
consumers.emplace_back([shared, i]() {
safe_print(" [消費者 ", i, "] 等待結果...");
int value = shared.get(); // 所有消費者都能取得相同的值
safe_print(" [消費者 ", i, "] 收到: ", value);
});
}
// 生產者
std::this_thread::sleep_for(std::chrono::milliseconds(100));
safe_print(" [生產者] 設定值 = 999");
promise.set_value(999);
for (auto& t : consumers) t.join();
std::cout << "\nshared_future 允許多個執行緒共享同一個結果\n";
std::cout << "(普通 future 的 get() 只能呼叫一次)\n\n";
}
// ============================================================
// 第六部分:例外傳遞
// ============================================================
double risky_computation(double x) {
if (x < 0) {
throw std::invalid_argument("輸入值不能為負數: " + std::to_string(x));
}
if (x == 0) {
throw std::runtime_error("除以零");
}
std::this_thread::sleep_for(std::chrono::milliseconds(50));
return std::sqrt(x) / x;
}
void demo_exception_propagation() {
std::cout << "========================================\n";
std::cout << " 例外傳遞(通過 future)\n";
std::cout << "========================================\n\n";
std::vector<double> inputs = {4.0, -1.0, 0.0, 16.0};
for (double x : inputs) {
auto future = std::async(std::launch::async, risky_computation, x);
try {
double result = future.get();
std::cout << " risky_computation(" << x << ") = " << result << "\n";
} catch (const std::invalid_argument& e) {
std::cout << " risky_computation(" << x << ") 錯誤: " << e.what() << "\n";
} catch (const std::runtime_error& e) {
std::cout << " risky_computation(" << x << ") 錯誤: " << e.what() << "\n";
}
}
std::cout << "\n例外會從工作執行緒傳遞到呼叫 get() 的執行緒\n\n";
}
// ============================================================
// 第七部分:平行計算範例
// ============================================================
// 分段平行加總
long long parallel_sum(const std::vector<int>& data, int num_tasks) {
int chunk_size = static_cast<int>(data.size()) / num_tasks;
std::vector<std::future<long long>> futures;
for (int i = 0; i < num_tasks; ++i) {
int start = i * chunk_size;
int end = (i == num_tasks - 1) ? static_cast<int>(data.size()) : start + chunk_size;
futures.push_back(std::async(std::launch::async,
[&data, start, end]() -> long long {
return std::accumulate(data.begin() + start,
data.begin() + end, 0LL);
}));
}
long long total = 0;
for (auto& f : futures) {
total += f.get();
}
return total;
}
// 平行質數計數
int count_primes_in_range(int start, int end) {
int count = 0;
for (int n = start; n < end; ++n) {
if (n < 2) continue;
bool is_prime = true;
for (int i = 2; i * i <= n; ++i) {
if (n % i == 0) { is_prime = false; break; }
}
if (is_prime) ++count;
}
return count;
}
void demo_parallel_computation() {
std::cout << "========================================\n";
std::cout << " 平行計算範例\n";
std::cout << "========================================\n\n";
// 平行加總
const int n = 10000000;
std::vector<int> data(n);
std::iota(data.begin(), data.end(), 1);
std::cout << "1. 平行加總 (1 到 " << n << "):\n";
auto t1 = std::chrono::steady_clock::now();
long long serial_sum = std::accumulate(data.begin(), data.end(), 0LL);
auto t2 = std::chrono::steady_clock::now();
auto serial_ms = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count();
t1 = std::chrono::steady_clock::now();
long long par_sum = parallel_sum(data, 4);
t2 = std::chrono::steady_clock::now();
auto par_ms = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count();
std::cout << " 序列加總: " << serial_sum << " (" << serial_ms << " ms)\n";
std::cout << " 平行加總: " << par_sum << " (" << par_ms << " ms, 4 任務)\n";
std::cout << " 結果" << (serial_sum == par_sum ? "一致 ✓" : "不一致 ✗") << "\n";
// 平行質數計數
std::cout << "\n2. 平行質數計數 (1 到 100000):\n";
const int range = 100000;
const int tasks = 4;
int chunk = range / tasks;
std::vector<std::future<int>> prime_futures;
t1 = std::chrono::steady_clock::now();
for (int i = 0; i < tasks; ++i) {
int start = i * chunk;
int end = (i == tasks - 1) ? range : start + chunk;
prime_futures.push_back(
std::async(std::launch::async, count_primes_in_range, start, end));
}
int total_primes = 0;
for (auto& f : prime_futures) {
total_primes += f.get();
}
t2 = std::chrono::steady_clock::now();
par_ms = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count();
std::cout << " 1 到 " << range << " 之間有 " << total_primes
<< " 個質數 (" << par_ms << " ms)\n";
std::cout << "\n";
}
// ============================================================
// 第八部分:模擬非同步檔案處理
// ============================================================
struct FileData {
std::string filename;
std::string content;
std::size_t size;
};
FileData async_read_file(const std::string& filename) {
safe_print(" 讀取 ", filename, "...");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::string content = "File content of " + filename + " (模擬資料)";
return {filename, content, content.size()};
}
std::string async_process_file(const FileData& data) {
safe_print(" 處理 ", data.filename, "...");
std::this_thread::sleep_for(std::chrono::milliseconds(50));
std::ostringstream oss;
oss << "已處理: " << data.filename << " (" << data.size << " bytes)";
return oss.str();
}
void demo_async_file_processing() {
std::cout << "========================================\n";
std::cout << " 非同步檔案處理模擬\n";
std::cout << "========================================\n\n";
std::vector<std::string> filenames = {
"config.json", "data.csv", "log.txt", "report.html"
};
auto start = std::chrono::steady_clock::now();
// 階段 1:平行讀取所有檔案
std::vector<std::future<FileData>> read_futures;
for (const auto& name : filenames) {
read_futures.push_back(
std::async(std::launch::async, async_read_file, name));
}
// 階段 2:讀取完成後平行處理
std::vector<std::future<std::string>> process_futures;
for (auto& rf : read_futures) {
FileData data = rf.get(); // 等待讀取完成
process_futures.push_back(
std::async(std::launch::async, async_process_file, data));
}
// 收集結果
std::cout << "\n 處理結果:\n";
for (auto& pf : process_futures) {
std::cout << " " << pf.get() << "\n";
}
auto end = std::chrono::steady_clock::now();
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
std::cout << "\n 總耗時: " << ms << " ms\n";
std::cout << " (若序列執行需 " << filenames.size() * 150 << " ms)\n\n";
}
// ============================================================
// 主程式
// ============================================================
int main() {
std::cout << "╔══════════════════════════════════════════╗\n";
std::cout << "║ C++17 async、future 與 promise ║\n";
std::cout << "╚══════════════════════════════════════════╝\n\n";
demo_async_basics();
demo_launch_policies();
demo_future_operations();
demo_promise_future();
demo_shared_future();
demo_exception_propagation();
demo_parallel_computation();
demo_async_file_processing();
std::cout << "=== 程式結束 ===\n";
return 0;
}
Articoli correlati
C++
c
Aggiornato 2026-07-21
deviceAlpha.h
deviceAlpha.h — c source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/deviceAlpha.h).
Leggi l'articolo →
C++
c
Aggiornato 2026-07-21
finalproject.c
finalproject.c — c source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/finalproject.c).
Leggi l'articolo →
C++
cpp
Aggiornato 2026-07-21
finalproject.cpp
finalproject.cpp — cpp source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/finalproject.cpp).
Leggi l'articolo →
C++
c
Aggiornato 2026-07-21
deviceAlpha.h
deviceAlpha.h — c source code from the C++ learning materials (C++/Mavis_Homework/Lab8/deviceAlpha.h).
Leggi l'articolo →
C++
c
Aggiornato 2026-07-21
lab8.c
lab8.c — c source code from the C++ learning materials (C++/Mavis_Homework/Lab8/lab8.c).
Leggi l'articolo →
C++
cpp
Aggiornato 2026-07-21
lab8.cpp
lab8.cpp — cpp source code from the C++ learning materials (C++/Mavis_Homework/Lab8/lab8.cpp).
Leggi l'articolo →