题目
编写程序,演示现代 C++11 原生多线程并发编程体系。创建多个 std::thread 并发递增全局共享计数器:首先剖析在无同步保护下多线程并发写入导致的数据竞争(Data Race)与结果严重偏离现象;随后引入 std::mutex 互斥锁,并使用 RAII 范式的 std::lock_guard 自动管理锁生命周期(离开作用域自动释放),彻底杜绝由于异常或提前退出造成的死锁灾难,最终保证并发累加结果的 100% 精确性。
输入格式:无需外部输入。
输出格式:输出多线程并发启动、各线程交替加锁工作以及最终数据同步汇总结果。
数据范围与约定:C++11 多线程、互斥量 mutex、lock_guard RAII 防死锁、join 线程汇聚。
思路与算法
1. 数据竞争(Data Race)的根源count++ 在 CPU 底层由三条汇编指令构成:读取内存到寄存器、寄存器加 1、写回内存。多线程交错执行会导致指令覆盖,产生严重脏数据,在 C++ 标准中这属于未定义行为(UB)。
2. 严禁手工 lock/unlock
若手写 mtx.lock() 和 mtx.unlock(),如果在锁区间内发生了异常或提前 return,unlock 将被永远跳过,整个进程彻底陷入死锁。
3. std::lock_guard 的 RAII 保证std::lock_guard<std::mutex> lock(mtx); 在构造时加锁,在析构时由编译器无条件保证解锁,是编写健壮多线程程序的第一法则。
4. 线程汇聚 join()
在主线程销毁前,必须对所有子线程显式调用 t.join()(等待完成)或 t.detach()(后台分离)。若一个 std::thread 在可结合状态(joinable)下被析构,会导致进程调用 std::terminate() 异常崩溃!
完整程序
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
const int NUM_THREADS = 5;
const int INCREMENTS_PER_THREAD = 10000;
long long globalCounter = 0;
std::mutex gMutex; // 全局互斥锁
void safeWorker(int threadId) {
for (int i = 0; i < INCREMENTS_PER_THREAD; ++i) {
// 关键:使用 RAII 锁守卫 lock_guard,作用域结束自动释放锁,严防死锁
std::lock_guard<std::mutex> lock(gMutex);
++globalCounter;
}
}
int main() {
std::cout << "===== C++ 练习100题 第100题:多线程并发与互斥同步 =====\n";
unsigned hc = std::thread::hardware_concurrency();
std::cout << "硬件并发核心支持线程数: " << hc << " (大于 0: " << (hc > 0 ? "是" : "否") << ")\n";
std::cout << "并发启动 " << NUM_THREADS << " 个线程,每个线程安全累加 "
<< INCREMENTS_PER_THREAD << " 次...\n\n";
std::vector<std::thread> threadPool;
threadPool.reserve(NUM_THREADS);
// 1. 批量启动子线程并发作业
for (int i = 0; i < NUM_THREADS; ++i) {
threadPool.emplace_back(safeWorker, i + 1);
}
// 2. 主线程汇聚等待所有子线程圆满完成
for (auto& t : threadPool) {
if (t.joinable()) {
t.join(); // 阻塞等待子线程执行完毕并回收资源
}
}
long long expected = static_cast<long long>(NUM_THREADS) * INCREMENTS_PER_THREAD;
std::cout << "所有子线程已全部平稳汇聚结束。\n";
std::cout << "实际累计计数值: " << globalCounter << "\n";
std::cout << "期望理论计数值: " << expected << "\n";
std::cout << "校验结论: " << (globalCounter == expected ? "【100% 数据一致,互斥同步成功】" : "数据竞争错误") << "\n";
return 0;
}运行示例
输出:
===== C++ 练习100题 第100题:多线程并发与互斥同步 =====
硬件并发核心支持线程数: 2 (大于 0: 是)
并发启动 5 个线程,每个线程安全累加 10000 次...
所有子线程已全部平稳汇聚结束。
实际累计计数值: 50000
期望理论计数值: 50000
校验结论: 【100% 数据一致,互斥同步成功】