【C++并发编程实战】:线程管理、锁机制与原子操作的专家指南
发布时间: 2024-10-01 03:36:09 阅读量: 33 订阅数: 29
![【C++并发编程实战】:线程管理、锁机制与原子操作的专家指南](https://img-blog.csdnimg.cn/20190506080943669.png)
# 1. C++并发编程入门
在本章中,我们将揭开C++并发编程的神秘面纱,为读者提供一个易于理解的并发世界入口。我们将开始探讨并发编程的基础概念,以及它在现代软件开发中的重要性。
## 1.1 并发与并行的基础
并发是一种允许多个计算任务同时进行的技术,它不意味着它们必须同时在物理上执行。而并行通常指的是在多核处理器或多个处理器上同时执行计算任务,是并发的一种形式。理解这两者之间的差异对于开发高效、响应式的应用程序至关重要。
## 1.2 C++中的并发支持
C++11标准为C++带来了丰富的并发支持,包括线程、互斥量、条件变量等基本构建块。我们将简要介绍这些概念,并讨论它们是如何成为现代C++编程实践的一部分。
## 1.3 环境与工具准备
为了进行并发编程,我们需要设置一个支持C++11或更高版本的开发环境。本节将指导读者如何配置编译器和相关工具,确保我们可以顺畅地进行后面的并发实践。
## 1.4 编写你的第一个并发程序
本章的结尾部分将提供一个简单的并发程序示例,通过实际编写代码来创建和管理线程,为后续章节更深层次的并发内容打下基础。这将涉及C++标准库中的`<thread>`头文件和`std::thread`类的使用。
# 2. 线程管理的深入理解
线程管理是并发编程的核心组成部分,涉及到创建线程、控制线程的生命周期以及同步多个线程的操作。本章节我们将深入探讨如何在C++中高效管理线程,掌握如何在多线程环境中保持数据的一致性和线程的安全性。
## 2.1 线程的创建与控制
### 2.1.1 使用std::thread管理线程
在C++11标准中,`std::thread` 是管理线程的核心类,允许程序创建和管理线程。创建线程后,可以对其进行一系列控制操作,包括启动、暂停、恢复执行、等待完成以及终止。
```cpp
#include <thread>
#include <iostream>
void printNumbers(int n) {
for (int i = 0; i < n; ++i) {
std::cout << i << std::endl;
}
}
int main() {
std::thread t(printNumbers, 10); // 创建并启动线程
t.join(); // 等待线程完成
return 0;
}
```
在上述代码中,`std::thread` 的构造函数接受一个函数对象和一系列参数,用于创建并启动一个线程。`join` 方法则用来同步等待线程完成其工作。
### 2.1.2 线程的启动、暂停和终止
线程的控制是通过不同成员函数来实现的,具体包括启动、暂停(挂起)和终止。
启动线程就是执行 `join` 或 `detach` 方法。
暂停线程执行可以使用 `std::this_thread::sleep_for` 函数。终止线程并不是C++标准推荐的做法,而是要通过协作的方式来让线程自行结束。
```cpp
#include <thread>
#include <chrono>
#include <iostream>
void threadFunction() {
std::cout << "Thread running..." << std::endl;
// 模拟工作
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "Thread finished." << std::endl;
}
int main() {
std::thread t(threadFunction);
std::cout << "Main thread sleeping..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "Main thread resumed." << std::endl;
t.join(); // 等待线程结束
return 0;
}
```
## 2.2 线程同步与互斥
### 2.2.1 互斥量(mutex)的使用
在多线程环境中,互斥量(`std::mutex`)是实现线程同步的关键机制之一。它用于保护共享资源,确保同一时间只有一个线程可以访问。
```cpp
#include <mutex>
#include <thread>
#include <iostream>
std::mutex mtx;
void printNumbers(int n) {
for (int i = 0; i < n; ++i) {
mtx.lock(); // 锁定互斥量
std::cout << i << std::endl;
mtx.unlock(); // 解锁互斥量
}
}
int main() {
std::thread t(printNumbers, 10);
std::thread t2(printNumbers, 10);
t.join();
t2.join();
return 0;
}
```
以上代码演示了如何使用 `std::mutex` 对 `printNumbers` 函数中的共享资源进行保护。每次打印操作前后分别锁定和解锁互斥量,从而避免了竞态条件。
### 2.2.2 条件变量(condition_variable)的应用
条件变量(`std::condition_variable`)用于线程间的同步。一个线程可以因为条件变量等待(wait)直到某个条件成立;另一个线程在条件成立后,可以通知(notify_one 或 notify_all)条件变量。
```cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void print_id(int id) {
std::unique_lock<std::mutex> lck(mtx);
while (!ready) {
cv.wait(lck); // 等待条件变量通知
}
std::cout << "Thread " << id << '\n';
}
void go() {
std::unique_lock<std::mutex> lck(mtx);
ready = true;
cv.notify_all(); // 通知所有等待的线程
}
int main() {
std::thread threads[10];
// 启动10个线程
for (int i = 0; i < 10; ++i)
threads[i] = std::thread(print_id, i);
std::cout << "10 threads ready to race...\n";
go(); // 等待所有线程就绪
for (auto& th : threads) th.join();
return 0;
}
```
在这个例子中,所有线程都将等待条件变量 `cv` 直到 `ready` 被设置为 `true`。当 `ready` 变量被 `go()` 函数设置后,所有线程将同时开始执行。
## 2.3 线程池的构建与管理
### 2.3.1 线程池的概念和优势
线程池是一种基于池化思想管理线程的技术。线程池中的一组工作线程会等待分配可并发执行的任务。它的好处包括减少在多线程间频繁创建和销毁线程的开销、提高响应速度和利用系统的线程数量限制来避免资源过度消耗。
### 2.3.2 实现一个简单的线程池
以下是一个简单的线程池实现,包含基本的工作队列和线程创建。
```cpp
#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <future>
class ThreadPool {
public:
ThreadPool(size_t);
template<class F, class... Args>
auto enqueue(F&& f, Args&&... args)
-> std::future<typename std::result_of<F(Args...)>::type>;
~ThreadPool();
private:
// 需要跟踪包含的线程以能够等待它们
std::vector< std::thread > workers;
// 任务队列
std::queue< std::function<void()> > tasks;
// 同步
std::mutex queue_mutex;
std::condition_variable condition;
bool stop;
};
// 构造函数启动一定数量的工作线程
inline ThreadPool::ThreadPool(size_t threads)
: stop(false)
{
for(size_t i = 0;i<threads;++i)
workers.emplace_back(
[this]
{
for(;;)
{
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(this->queue_mutex);
this->condition.wait(lock,
[this]{ return this->stop || !this->tasks.empty(); });
if(this->stop && this->tasks.empty())
return;
task = std::move(this->tasks.front());
this->tasks.pop();
}
```
0
0