1. 并行求和
任务说明
本案例要求实现一个并行求和程序:将一个大数组(例如 10,000,000 个整数)分割为多个子区间,由多个线程分别计算局部和,最后合并得到总和,并与串行求和结果对比以验证正确性。核心目标是理解线程划分与结果合并的基本模式。
实现方案
采用 C++11 标准线程库,使用固定线程数(例如 4 或 8),将数组均匀切分为连续块,每个线程负责一个块。使用 std::atomic<long long> 或互斥锁保护全局累加变量,避免数据竞争。为简化实现,使用 std::thread 手动管理线程生命周期,不引入额外依赖。
代码实现
#include <iostream>
#include <vector>
#include <thread>
#include <atomic>
#include <chrono>
#include <cstdlib>
// 串行求和(用于验证)
long long serial_sum(const std::vector<int>& data) {
long long sum = 0;
for (int v : data) sum += v;
return sum;
}
// 并行求和:将数组切分为 num_threads 块,每块由独立线程累加
long long parallel_sum(const std::vector<int>& data, int num_threads) {
std::atomic<long long> total{0};
size_t n = data.size();
size_t chunk = (n + num_threads - 1) / num_threads; // 向上取整
std::vector<std::thread> threads;
threads.reserve(num_threads);
for (int t = 0; t < num_threads; ++t) {
size_t start = t * chunk;
size_t end = std::min(start + chunk, n);
if (start >= n) break; // 防止越界
threads.emplace_back([&data, &total, start, end]() {
long long local = 0;
for (size_t i = start; i < end; ++i) {
local += data[i];
}
total.fetch_add(local, std::memory_order_relaxed);
});
}
for (auto& th : threads) th.join();
return total.load();
}
int main() {
const size_t N = 10'000'000;
const int NUM_THREADS = 4;
// 生成固定随机种子,保证可复现
std::vector<int> data(N);
std::srand(42);
for (auto& v : data) v = std::rand() % 100;
// 串行结果
long long s_sum = serial_sum(data);
// 并行结果
long long p_sum = parallel_sum(data, NUM_THREADS);
// 输出对比
std::cout << "串行求和: " << s_sum << std::endl;
std::cout << "并行求和: " << p_sum << std::endl;
std::cout << "结果一致: " << (s_sum == p_sum ? "是" : "否") << std::endl;
return 0;
}
编译与运行
g++ -std=c++11 -O2 -pthread parallel_sum.cpp -o parallel_sum
./parallel_sum
验证方法
程序输出三行信息:串行求和值、并行求和值、以及两者是否一致。判定标准:“结果一致”输出为“是”,且串行与并行数值相同。由于使用固定随机种子(42),每次运行生成的数组完全一致,因此输出结果可稳定复现。
预期输出
串行求和: 495049500
并行求和: 495049500
结果一致: 是
(注:以上数值由固定种子与固定数组长度直接推出,非实测结果。)