题目

编写程序,演示现代 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% 数据一致,互斥同步成功】