学懂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 的深入详解
相关推荐
binishuaio4 分钟前
Java 第11天 (git版本控制器基础用法)
java·开发语言·git
zz.YE6 分钟前
【Java SE】StringBuffer
java·开发语言
就是有点傻10 分钟前
WPF中的依赖属性
开发语言·wpf
洋24018 分钟前
C语言常用标准库函数
c语言·开发语言
进击的六角龙20 分钟前
Python中处理Excel的基本概念(如工作簿、工作表等)
开发语言·python·excel
wrx繁星点点21 分钟前
状态模式(State Pattern)详解
java·开发语言·ui·设计模式·状态模式
NoneCoder38 分钟前
Java企业级开发系列(1)
java·开发语言·spring·团队开发·开发
苏三有春38 分钟前
PyQt5实战——UTF-8编码器功能的实现(六)
开发语言·qt
脉牛杂德41 分钟前
多项式加法——C语言
数据结构·c++·算法
legend_jz43 分钟前
STL--哈希
c++·算法·哈希算法