C++多线程教程-1.2.1 C++11/14/17 并发特性迭代

本部分内容属于:
C++并发编程系列-基于标准库
第一部分:并发编程基础与C++线程模型
1.2 C++的并发编程演进
1.2.1 C++11/14/17 并发特性迭代
其它章节内容请查看对应章节。

1.2.1 C++11/14/17 并发特性迭代

在C++11之前,C++标准完全没有对并发编程提供原生支持,开发者只能依赖平台特定的API(如Windows的CreateThread、POSIX的pthread)实现多线程,代码的可移植性和安全性极差。C++11首次将并发编程纳入标准库,奠定了跨平台并发的基础;C++14对已有特性进行了轻量级增强,提升易用性;C++17则完善了核心组件,新增了实用工具,让标准并发库更完整、更高效。

一、C++11:并发编程的"开山之作"

C++11是C++并发编程的里程碑,核心目标是提供跨平台的线程抽象和基础同步原语,解决此前依赖平台API的移植性问题。其核心并发特性可分为三类:

1. 线程基础抽象

  • std::thread:操作系统线程的标准封装,支持创建、启动、等待(join)、分离(detach)线程,替代平台原生线程创建接口。

  • std::this_thread命名空间:提供线程级操作(sleep_foryieldget_id),统一不同平台的线程控制逻辑。

  • std::thread_local:线程本地存储(TLS),保证变量在每个线程有独立副本,避免全局变量的线程安全问题。

2. 同步原语

  • 基础互斥量:std::mutexstd::recursive_mutexstd::timed_mutexstd::recursive_timed_mutex,解决共享数据竞争。

  • RAII锁管理器:std::lock_guard(轻量级独占锁)、std::unique_lock(灵活独占锁),避免手动解锁导致的资源泄漏。

  • 条件变量:std::condition_variablestd::condition_variable_any,实现线程间的等待-通知通信。

  • 原子操作:std::atomic模板及内存序(memory_order_*),支持无锁的原子读写,替代部分场景下的互斥量。

3. 异步操作框架

  • std::future/std::promise:实现线程间的结果传递,解决"生产者-消费者"模型中结果同步的问题。

  • std::packaged_task:包装可调用对象为异步任务,关联std::future获取结果。

  • std::async:简化异步任务创建,自动管理底层线程(支持launch::async/launch::deferred两种策略)。

C++11核心并发特性示例:基础线程与互斥量
cpp 复制代码
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>

// 全局共享变量
int shared_counter = 0;
// 全局互斥量,保护共享变量
std::mutex counter_mutex;

// 线程函数:对共享变量累加
void increment_counter(int iterations) {
    for (int i = 0; i < iterations; ++i) {
        // RAII锁:构造时加锁,析构时解锁,避免死锁
        std::lock_guard<std::mutex> lock(counter_mutex);
        shared_counter++;
        // 模拟耗时操作,让出CPU(C++11 std::this_thread::yield)
        std::this_thread::yield();
    }
}

int main() {
    // 创建2个线程,每个线程累加10000次
    std::vector<std::thread> threads;
    threads.emplace_back(increment_counter, 10000);
    threads.emplace_back(increment_counter, 10000);

    // 等待所有线程完成(C++11 std::thread::join)
    for (auto& t : threads) {
        if (t.joinable()) {
            t.join();
        }
    }

    // 输出最终结果(预期为20000)
    std::cout << "Final counter value: " << shared_counter << std::endl;

    return 0;
}
代码说明:
  1. 核心组件

    • std::mutex:保护shared_counter避免数据竞争,确保每次只有一个线程修改该变量;

    • std::lock_guard:RAII封装互斥量,即使increment_counter抛出异常,析构时也会自动解锁;

    • std::thread:创建线程对象,emplace_back直接构造线程(C++11移动语义支持);

    • std::this_thread::yield:让出CPU时间片,模拟实际场景中的线程切换。

  2. 编译与运行

    • 编译命令(GCC/Clang):g++ -std=c++11 thread_demo.cpp -o thread_demo -pthread

    • 运行结果:Final counter value: 20000(若无互斥量,结果会随机小于20000,体现数据竞争)。

二、C++14:轻量级增强,提升易用性

C++14并未新增核心并发组件,而是针对C++11的已有特性做易用性优化,降低开发门槛:

1. 原子操作增强

  • 支持对std::atomic<T>的泛型lambda操作,简化原子类型的自定义逻辑;

  • 允许std::atomic对更多类型(如自定义POD类型)的隐式推导,减少代码冗余。

2. 异步操作优化

  • std::shared_future支持移动和拷贝的更灵活语义,允许多个线程共享同一个异步结果;

  • 修复std::async在部分编译器中的行为不一致问题(如launch::async策略的线程创建时机);

  • std::condition_variable_any支持更多自定义锁类型,不再局限于标准互斥量。

3. 语法糖简化并发代码

  • 泛型lambda配合std::thread,简化线程函数的定义(无需单独写函数,直接内联lambda)。
C++14增强特性示例:泛型lambda+原子操作
cpp 复制代码
#include <iostream>
#include <thread>
#include <atomic>
#include <vector>

int main() {
    // C++11已支持,但C++14泛型lambda让用法更灵活
    std::atomic<int> sum(0);
    const int thread_count = 4;
    const int iterations = 1000;

    // C++14泛型lambda作为线程函数
    auto add_task = [&sum](int start, int end) {
        for (int i = start; i < end; ++i) {
            // C++11原子操作,C++14无语法变化,但lambda泛型简化调用
            sum.fetch_add(i, std::memory_order_relaxed);
        }
    };

    std::vector<std::thread> threads;
    for (int i = 0; i < thread_count; ++i) {
        int start = i * iterations;
        int end = (i + 1) * iterations;
        threads.emplace_back(add_task, start, end);
    }

    // 等待所有线程完成
    for (auto& t : threads) {
        t.join();
    }

    // 计算预期结果:0+1+...+3999 = (3999*4000)/2 = 7998000
    std::cout << "Atomic sum result: " << sum.load() << std::endl;

    return 0;
}
代码说明:
  1. C++14核心优化点

    • 泛型lambdaadd_task无需显式指定参数类型(int start, int end),编译器自动推导,简化线程函数编写;

    • std::atomic::fetch_addmemory_order_relaxed(松散内存序)在C++11已支持,但C++14让原子操作与泛型结合更自然。

  2. 编译与运行

    • 编译命令:g++ -std=c++14 atomic_demo.cpp -o atomic_demo -pthread

    • 运行结果:Atomic sum result: 7998000(原子操作保证结果准确,无数据竞争)。

三、C++17:完善核心组件,新增实用工具

C++17是C++11并发模型的"补全版",解决了C++11/14中部分组件的痛点,新增了高价值工具,核心改进如下:

1. 新增核心同步组件

  • std::scoped_lock:替代std::lock + std::lock_guard,支持多互斥量无死锁加锁,且是类型安全的RAII锁;

  • std::shared_mutex/std::shared_timed_mutex:正式纳入标准的读写锁(C++14仅为实验性),实现"多读单写"的高效同步;

  • std::shared_lock:配合std::shared_mutex使用的共享锁,支持多个读线程同时持有锁,写线程独占锁。

2. 并行算法(std::execution)

  • 新增std::execution命名空间,提供三种执行策略:

    • std::execution::seq:串行执行(默认);

    • std::execution::par:并行执行(多线程);

    • std::execution::par_unseq:并行+向量化执行(更激进的并行优化);

  • 标准库算法(std::sortstd::for_eachstd::find等)支持传入执行策略,自动实现并行化,无需手动创建线程。

3. 其他优化

  • std::invoke:统一可调用对象的调用方式(函数、成员函数、lambda、函数对象),简化线程函数的适配;

  • std::byte:与原子操作兼容,支持更安全的内存字节级操作;

  • 修复std::thread在部分平台的兼容性问题,明确joinable()的状态判断规则。

C++17核心新增特性示例:std::scoped_lock + 并行排序
cpp 复制代码
#include <iostream>
#include <thread>
#include <mutex>
#include <shared_mutex>
#include <algorithm>
#include <vector>
#include <execution> // C++17并行算法头文件

// 读写锁示例:多读单写
class SharedData {
private:
    std::vector<int> data;
    // C++17正式标准的读写锁
    std::shared_mutex rw_mutex;

public:
    // 写操作:独占锁
    void add_data(int value) {
        // 独占锁:写线程独占,阻塞所有读/写线程
        std::lock_guard<std::shared_mutex> lock(rw_mutex);
        data.push_back(value);
        std::cout << "Write thread " << std::this_thread::get_id() << " added: " << value << std::endl;
    }

    // 读操作:共享锁
    void print_data() {
        // 共享锁:多个读线程可同时持有,阻塞写线程
        std::shared_lock<std::shared_mutex> lock(rw_mutex);
        std::cout << "Read thread " << std::this_thread::get_id() << " data size: " << data.size() << std::endl;
    }

    // C++17并行排序:自动多线程排序
    void sort_data_parallel() {
        // 独占锁:排序时禁止读/写
        std::scoped_lock lock(rw_mutex); // C++17 scoped_lock替代lock_guard
        // 并行执行策略:自动多线程排序
        std::sort(std::execution::par, data.begin(), data.end());
        std::cout << "Sort thread " << std::this_thread::get_id() << " sorted data" << std::endl;
    }
};

int main() {
    SharedData sd;

    // 1. 多个写线程添加数据
    std::vector<std::thread> write_threads;
    for (int i = 0; i < 5; ++i) {
        write_threads.emplace_back(&SharedData::add_data, &sd, i * 10);
    }
    for (auto& t : write_threads) {
        t.join();
    }

    // 2. 多个读线程读取数据
    std::vector<std::thread> read_threads;
    for (int i = 0; i < 3; ++i) {
        read_threads.emplace_back(&SharedData::print_data, &sd);
    }
    for (auto& t : read_threads) {
        t.join();
    }

    // 3. 并行排序数据
    std::thread sort_thread(&SharedData::sort_data_parallel, &sd);
    sort_thread.join();

    return 0;
}
代码说明:
  1. C++17核心新增点

    • std::shared_mutex:正式标准的读写锁,add_data(写)用lock_guard独占,print_data(读)用shared_lock共享,提升读并发效率;

    • std::scoped_lock:替代std::lock_guard,语法更简洁,且支持多互斥量(如std::scoped_lock lock(m1, m2)),自动避免死锁;

    • std::execution::par:并行排序策略,std::sort自动创建线程完成排序,无需手动管理线程池。

  2. 编译与运行

    • 编译命令:g++ -std=c++17 shared_mutex_demo.cpp -o shared_mutex_demo -pthread

    • 运行结果示例(线程ID随机):

      Plain 复制代码
      Write thread 140709284798272 added: 0
      Write thread 140709276405568 added: 10
      Write thread 140709268012864 added: 20
      Write thread 140709259620160 added: 30
      Write thread 140709251227456 added: 40
      Read thread 140709242834752 data size: 5
      Read thread 140709234442048 data size: 5
      Read thread 140709226049344 data size: 5
      Sort thread 140709217656640 sorted data

四、C++11/14/17 并发特性迭代总结表

版本 核心新增/优化 解决的核心问题
C++11 1. std::thread/互斥量/条件变量 2. std::atomic/内存序 3. std::future/promise/async 无标准并发库,依赖平台API,移植性差
C++14 1. 泛型lambda适配并发代码 2. std::shared_future增强 3. 原子操作泛型支持 C++11并发代码冗余,lambda使用不灵活
C++17 1. std::scoped_lock(多互斥量无死锁) 2. std::shared_mutex(读写锁) 3. 并行算法(std::execution) C++11/14同步方式单一,手动并行开发成本高

总结

  1. C++11是并发编程的基础,首次提供跨平台的线程、同步、异步核心组件,解决了平台依赖问题;

  2. C++14以"易用性优化"为主,通过泛型lambda等语法糖简化并发代码编写,无核心组件新增;

  3. C++17完善了同步组件(读写锁、scoped_lock),新增并行算法,大幅降低并行开发成本,是C++11并发模型的重要补全。

这些迭代的核心逻辑是:从"能实现并发"(C++11)→"易实现并发"(C++14)→"高效实现并发"(C++17),逐步降低开发门槛,提升并发代码的安全性和性能。

相关推荐
80530单词突击赢2 小时前
C++入门指南:从零到精通
开发语言·c++
小突突突2 小时前
浅谈Java中的反射
java·开发语言
csbysj20202 小时前
JSP 发送邮件教程
开发语言
Tansmjs2 小时前
C++编译期数据结构
开发语言·c++·算法
金枪不摆鳍2 小时前
算法-字典树
开发语言·算法
diediedei3 小时前
C++类型推导(auto/decltype)
开发语言·c++·算法
索荣荣3 小时前
Java动态代理实战:从原理到精通
java·开发语言
兩尛3 小时前
c++的数组和Java数组的不同
java·开发语言·c++
roman_日积跬步-终至千里3 小时前
【Java并发】多线程/并发问题集
java·开发语言