C++多线程编程和并发控制是现代软件开发中非常重要的一部分,它允许程序同时执行多个任务,从而提高程序的性能和响应能力。下面我将简要介绍C++中多线程编程和并发控制的基本概念、API以及一些常见的实践。
1. C++11及以后的线程支持
从C++11开始,C++标准库引入了<thread>
头文件,它提供了基本的线程支持。你可以使用std::thread
类来创建和管理线程。
示例:
cpp复制代码
#include <iostream> | |
#include <thread> | |
void hello() { | |
std::cout << "Hello from thread!\n"; | |
} | |
int main() { | |
std::thread t(hello); | |
t.join(); // 等待线程完成 | |
return 0; | |
} |
2. 并发控制
当多个线程需要访问和修改共享资源时,就需要进行并发控制,以防止数据竞争和不一致的状态。C++提供了几种并发控制机制:
2.1 互斥锁(Mutex)
互斥锁是最常见的并发控制机制,它可以确保同一时间只有一个线程可以访问某个特定的代码段(称为临界区)。C++标准库提供了std::mutex
类来实现互斥锁。
示例:
cpp复制代码
#include <iostream> | |
#include <thread> | |
#include <mutex> | |
std::mutex mtx; // 全局互斥锁 | |
int counter = 0; | |
void increment() { | |
for (int i = 0; i < 100000; ++i) { | |
std::lock_guard<std::mutex> lock(mtx); // 使用lock_guard自动管理锁的生命周期 | |
++counter; | |
} | |
} | |
int main() { | |
std::thread t1(increment); | |
std::thread t2(increment); | |
t1.join(); | |
t2.join(); | |
std::cout << "Final counter: " << counter << '\n'; | |
return 0; | |
} |
2.2 条件变量(Condition Variable)
条件变量允许线程等待某个条件成立。这通常与互斥锁一起使用,以在多个线程之间同步。C++标准库提供了std::condition_variable
类。
2.3 原子操作(Atomic Operations)
对于简单的数据类型(如int、指针等),C++提供了原子操作来确保操作的原子性,从而避免数据竞争。C++标准库提供了std::atomic
模板类。
3. 其他并发工具
- 线程局部存储(Thread-Local Storage, TLS):允许每个线程存储其自己的数据副本。
- 屏障(Barrier):允许一组线程在某个点上同步。
- 读写锁(Read-Write Lock):允许多个线程同时读取共享资源,但只允许一个线程写入。
4. 实践建议
- 避免共享数据:尽可能避免线程之间共享数据。如果必须共享,请使用适当的并发控制机制。
- 使用RAII管理资源:使用如
std::lock_guard
这样的RAII类来自动管理锁的生命周期,以避免死锁和忘记释放锁的问题。 - 避免过度同步:过多的同步会导致性能下降。尽量只同步必要的部分。
- 注意异常安全:在多线程环境中,异常处理变得更加复杂。确保你的代码能够妥善处理异常,并避免在异常处理过程中引入新的问题。