C++学习系列(9):多线程编程基础
1. 引言
随着多核 CPU 的普及,多线程编程 成为 C++ 开发的重要技能。C++11 引入了 <thread> 头文件,使得多线程编程更加简单和现代化。
本篇博客将介绍:
- 多线程的基本概念
- 如何创建和管理线程
- 线程同步机制
- C++11
std::thread的使用 - 互斥锁(Mutex)和条件变量
2. 线程的基本概念
在 C++ 中,线程(Thread) 是 进程(Process) 内部的一个执行单元。一个进程可以包含多个线程,线程共享同一进程的资源(如内存、文件等)。
多线程的优势
✅ 提高 CPU 利用率:多个线程可以并行执行,提高效率
✅ 资源共享:同一进程的线程可以共享数据
✅ 响应更快:如 GUI 线程可以避免主线程阻塞
3. C++11 std::thread 创建线程
C++11 提供了 std::thread 作为标准线程库,使用非常简单。
3.1 使用 std::thread 创建线程
#include <iostream>
#include <thread>
void printMessage() {
std::cout << "Hello from thread!\n";
}
int main() {
std::thread t(printMessage); // 创建新线程
t.join(); // 等待线程执行完成
return 0;
}
📌 解析
std::thread t(printMessage);创建一个新线程t.join();等待线程执行完成,避免主线程提前退出
3.2 传递参数给线程
可以通过 std::thread 传递参数给线程函数:
#include <iostream>
#include <thread>
void printMessage(std::string message, int count) {
for (int i = 0; i < count; ++i) {
std::cout << message << " " << i << std::endl;
}
}
int main() {
std::thread t(printMessage, "Hello", 5);
t.join();
return 0;
}
📌 注意
- 传递 字符串参数 时,最好使用
std::ref(),否则std::thread会复制参数,导致额外的开销。
4. join() vs detach()
线程对象 std::thread 提供了两种管理方式:
| 方法 | 作用 | 适用场景 |
|---|---|---|
join() | 等待线程执行完成 | 需要同步等待线程执行 |
detach() | 让线程独立运行,主线程不会等待 | 后台任务,不关心执行结果 |
4.1 detach() 让线程后台运行
#include <iostream>
#include <thread>
#include <chrono>
void backgroundTask() {
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "后台任务完成\n";
}
int main() {
std::thread t(backgroundTask);
t.detach(); // 线程独立运行
std::cout << "主线程继续执行\n";
std::this_thread::sleep_for(std::chrono::seconds(3));
return 0;
}
📌 注意
detach()后,线程对象不再受管理,需要确保线程生命周期不会影响主线程。
5. 线程同步与互斥锁(Mutex)
多线程编程中,多个线程可能同时访问同一变量,导致 数据竞争(Race Condition)。C++ 提供 互斥锁(Mutex) 进行线程同步。
5.1 std::mutex 互斥锁
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx; // 互斥锁
int counter = 0;
void increaseCounter() {
for (int i = 0; i < 100000; ++i) {
std::lock_guard<std::mutex> lock(mtx); // 自动加锁解锁
++counter;
}
}
int main() {
std::thread t1(increaseCounter);
std::thread t2(increaseCounter);
t1.join();
t2.join();
std::cout << "最终计数值: " << counter << std::endl;
return 0;
}
📌 解析
std::mutex互斥锁保证同一时刻 只有一个线程 访问counterstd::lock_guard<std::mutex>自动管理锁,作用域结束时自动解锁
6. std::condition_variable 条件变量
条件变量(Condition Variable) 允许一个线程等待另一个线程的通知。
6.1 生产者-消费者模型
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
std::queue<int> buffer;
std::mutex mtx;
std::condition_variable cv;
void producer() {
for (int i = 0; i < 5; ++i) {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::lock_guard<std::mutex> lock(mtx);
buffer.push(i);
std::cout << "生产: " << i << std::endl;
cv.notify_one(); // 通知消费者
}
}
void consumer() {
for (int i = 0; i < 5; ++i) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return !buffer.empty(); }); // 等待生产者
int item = buffer.front();
buffer.pop();
std::cout << "消费: " << item << std::endl;
}
}
int main() {
std::thread t1(producer);
std::thread t2(consumer);
t1.join();
t2.join();
return 0;
}
📌 解析
cv.wait(lock, [] { return !buffer.empty(); });等待条件满足cv.notify_one();通知消费者线程- 生产者 推送数据,消费者 等待并消费
7. 线程池(Thread Pool)
C++17 及以后可以使用 std::async 或 std::thread 自己实现线程池:
#include <iostream>
#include <thread>
#include <vector>
void task(int id) {
std::cout << "任务 " << id << " 正在执行\n";
}
int main() {
std::vector<std::thread> pool;
for (int i = 0; i < 5; ++i) {
pool.emplace_back(task, i);
}
for (auto& t : pool) {
t.join();
}
return 0;
}
📌 多线程池可以提高任务执行效率,后续我们将深入探讨线程池的优化。
8. 总结
✅ std::thread 轻松创建多线程
✅ 使用 std::mutex 进行同步,防止数据竞争
✅ 条件变量 std::condition_variable 适用于线程通信
✅ 线程池是多线程优化的核心
在下一篇 C++学习系列(10) 中,我们将探讨 C++ STL 容器底层原理,敬请期待!🚀
💡 如果你喜欢这篇文章,欢迎点赞、收藏,并关注本系列!
472

被折叠的 条评论
为什么被折叠?



