学懂C++(二十三):高级教程——深入详解C++ 标准库的多线程支持

目录

[1. 创建、管理和操作线程:std::thread](#1. 创建、管理和操作线程:std::thread)

[2. 互斥量(Mutex)](#2. 互斥量(Mutex))

[3. 锁(Lock)](#3. 锁(Lock))

[4. 条件变量(Condition Variables)](#4. 条件变量(Condition Variables))

[5. 原子操作(Atomic Operations)](#5. 原子操作(Atomic Operations))

[6. 异步任务和 Futures](#6. 异步任务和 Futures)

[使用 std::async](#使用 std::async)

[使用 std::promise 和 std::future](#使用 std::promise 和 std::future)

总结


在现代软件开发中,多线程编程能够显著提高程序的性能和响应性。C++11 引入了许多新的特性,极大丰富了多线程编程的支持。以下将重点介绍 C++ 中的多线程相关技术,包括 std::thread、互斥量、锁、条件变量、原子操作以及异步任务和 Futures。

1. 创建、管理和操作线程:std::thread

std::thread 是 C++11 标准库中引入的类,用于创建和管理线程。

示例

cpp 复制代码
#include <iostream>
#include <thread>

void threadFunction() {
    std::cout << "Thread is running!" << std::endl;
}

int main() {
    // 创建线程
    std::thread t(threadFunction);
    
    // 等待线程完成
    if (t.joinable()) {
        t.join();  // 等待线程结束
    }

    std::cout << "Thread has finished." << std::endl;
    return 0;
}

输出

cpp 复制代码
Thread is running!
Thread has finished.

解释

  • std::thread 接受一个函数(或可调用对象)作为参数。
  • 使用 join() 函数等待线程完成,joinable() 用于检查线程是否可以被加入。

2. 互斥量(Mutex)

互斥量用于保护共享资源,防止数据竞争。C++ 提供了 std::mutexstd::recursive_mutex,后者允许同一线程多次锁定。

示例

cpp 复制代码
#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;

void printMessage(int id) {
    std::lock_guard<std::mutex> lock(mtx); // 自动管理锁的生命周期
    std::cout << "Thread ID: " << id << std::endl;
}

int main() {
    std::thread t1(printMessage, 1);
    std::thread t2(printMessage, 2);

    t1.join();
    t2.join();

    return 0;
}

输出

cpp 复制代码
Thread ID: 1
Thread ID: 2

(输出顺序可能会变,因为线程的调度是非确定性的。)

解释

  • std::lock_guard 在其作用域内自动锁定互斥量,并在作用域结束时自动解锁。
  • 使用 std::recursive_mutex 可以在同一线程中多次锁定。

3. 锁(Lock)

锁提供了管理互斥量的灵活性。std::unique_lock 提供更多的功能,可以控制锁的生命周期。

示例

cpp 复制代码
#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;

void printMessage(int id) {
    std::unique_lock<std::mutex> lock(mtx, std::defer_lock); // 延迟锁定
    lock.lock();  // 手动锁定
    std::cout << "Thread ID: " << id << std::endl;
    lock.unlock(); // 提前解锁
}

int main() {
    std::thread t1(printMessage, 1);
    std::thread t2(printMessage, 2);

    t1.join();
    t2.join();

    return 0;
}

输出

cpp 复制代码
Thread ID: 1
Thread ID: 2

(输出顺序可能会有所不同。)

解释

  • std::unique_lock 提供延迟锁定和提前解锁的功能,适用于需要更复杂锁管理的情况。

4. 条件变量(Condition Variables)

条件变量用于线程间的通知和等待。它们允许线程在特定条件满足时继续执行。

示例

cpp 复制代码
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void printMessage(int id) {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, [] { return ready; }); // 等待条件变量的通知
    std::cout << "Thread ID: " << id << std::endl;
}

void setReady() {
    std::this_thread::sleep_for(std::chrono::seconds(1));
    {
        std::lock_guard<std::mutex> lock(mtx);
        ready = true;
    }
    cv.notify_all(); // 通知所有等待的线程
}

int main() {
    std::thread t1(printMessage, 1);
    std::thread t2(printMessage, 2);

    setReady(); // 设置条件并通知

    t1.join();
    t2.join();

    return 0;
}

输出

cpp 复制代码
Thread ID: 1
Thread ID: 2

(两个线程会在条件满足后同时打印。)

解释

  • cv.wait 使线程等待直到条件满足。
  • cv.notify_all 唤醒所有等待的线程。

5. 原子操作(Atomic Operations)

std::atomic 支持无锁编程,确保在高并发情况下的线程安全。

示例

cpp 复制代码
#include <iostream>
#include <thread>
#include <atomic>

std::atomic<int> counter(0);

void incrementCounter() {
    for (int i = 0; i < 1000; ++i) {
        ++counter; // 原子操作
    }
}

int main() {
    std::thread t1(incrementCounter);
    std::thread t2(incrementCounter);

    t1.join();
    t2.join();

    std::cout << "Counter: " << counter.load() << std::endl; // 获取值
    return 0;
}

输出

cpp 复制代码
Counter: 2000

(两个线程各自增加计数器 1000 次,总和为 2000。)

解释

  • std::atomic<int> 提供线程安全的整数操作,无需使用互斥量。

6. 异步任务和 Futures

C++11 提供了 std::asyncstd::promisestd::future,用于异步任务和线程间通信。

示例

使用 std::async
cpp 复制代码
#include <iostream>
#include <future>

int asyncTask() {
    std::this_thread::sleep_for(std::chrono::seconds(1));
    return 42;
}

int main() {
    std::future<int> result = std::async(std::launch::async, asyncTask);
    std::cout << "Waiting for result..." << std::endl;
    std::cout << "Result: " << result.get() << std::endl; // 阻塞直到获取结果
    return 0;
}

输出

cpp 复制代码
Waiting for result...
Result: 42
使用 std::promisestd::future
cpp 复制代码
#include <iostream>
#include <thread>
#include <future>

void setPromiseValue(std::promise<int>& prom) {
    std::this_thread::sleep_for(std::chrono::seconds(1));
    prom.set_value(42); // 设置未来值
}

int main() {
    std::promise<int> prom;
    std::future<int> fut = prom.get_future();

    std::thread t(setPromiseValue, std::ref(prom));
    std::cout << "Waiting for result..." << std::endl;
    std::cout << "Result: " << fut.get() << std::endl; // 获取结果

    t.join();
    return 0;
}

输出

cpp 复制代码
Waiting for result...
Result: 42

解释

  • std::async 用于启动异步任务并返回 std::future
  • std::promisestd::future 用于实现线程间的结果传递。

总结

以上介绍了 C++ 多线程编程中的重要知识点,包括线程创建、互斥量、锁、条件变量、原子操作以及异步任务和 Futures。通过合理使用这些特性,可以有效地管理并发,提高程序的运行效率和安全性。在多线程编程中,确保线程安全和良好的资源管理是非常关键的。希望这些示例对您理解 C++ 的多线程开发有所帮助。

上一篇:学懂C++(二十二):高级教程------深入理解 C++ 多线程基础理论和概念
下一篇:学懂C++(二十四):高级教程------C++ 多线程编程中 std::thread 的深入详解
相关推荐
Charles Ray4 分钟前
C++学习笔记 —— 内存分配 new
c++·笔记·学习
重生之我在20年代敲代码4 分钟前
strncpy函数的使用和模拟实现
c语言·开发语言·c++·经验分享·笔记
爱上语文6 分钟前
Springboot的三层架构
java·开发语言·spring boot·后端·spring
编程零零七2 小时前
Python数据分析工具(三):pymssql的用法
开发语言·前端·数据库·python·oracle·数据分析·pymssql
2401_858286113 小时前
52.【C语言】 字符函数和字符串函数(strcat函数)
c语言·开发语言
铁松溜达py3 小时前
编译器/工具链环境:GCC vs LLVM/Clang,MSVCRT vs UCRT
开发语言·网络
everyStudy3 小时前
JavaScript如何判断输入的是空格
开发语言·javascript·ecmascript
C-SDN花园GGbond5 小时前
【探索数据结构与算法】插入排序:原理、实现与分析(图文详解)
c语言·开发语言·数据结构·排序算法
迷迭所归处6 小时前
C++ —— 关于vector
开发语言·c++·算法
架构文摘JGWZ6 小时前
Java 23 的12 个新特性!!
java·开发语言·学习