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

        

目录

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

2. 互斥量(Mutex)

3. 锁(Lock)

4. 条件变量(Condition Variables)

5. 原子操作(Atomic Operations)

6. 异步任务和 Futures

使用 std::async

使用 std::promise 和 std::future

总结


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

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

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

示例

#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;
}

输出

Thread is running!
Thread has finished.

解释

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

2. 互斥量(Mutex)

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

示例

#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;
}

输出

Thread ID: 1
Thread ID: 2

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

解释

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

3. 锁(Lock)

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

示例

#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;
}

输出

Thread ID: 1
Thread ID: 2

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

解释

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

4. 条件变量(Condition Variables)

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

示例

#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;
}

输出

Thread ID: 1
Thread ID: 2

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

解释

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

5. 原子操作(Atomic Operations)

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

示例

#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;
}

输出

Counter: 2000

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

解释

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

6. 异步任务和 Futures

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

示例

使用 std::async
#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;
}

输出

Waiting for result...
Result: 42

使用 std::promise 和 std::future
#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;
}

输出

Waiting for result...
Result: 42

解释

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

总结

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

上一篇:学懂C++(二十二):高级教程——深入理解 C++ 多线程基础理论和概念
下一篇:学懂C++(二十四):高级教程——C++ 多线程编程中 std::thread 的深入详解

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猿享天开

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值