C++11之前,C++标准没有内置的多线程支持,开发者在Windows平台需要使用CreateThread,在Linux平台需要使用pthread库,跨平台开发时需要做大量适配工作。C++11引入了<thread>、<mutex>、<condition_variable>等头文件,提供了统一的多线程编程接口,让跨平台多线程开发变得简单。

C++11多线程核心组件
1. 线程对象std::thread
std::thread是C++11中用于表示线程的类,创建线程时只需要传入可调用对象(函数、lambda表达式、函数对象等)和对应的参数即可。线程创建后会立即开始执行,需要注意线程的生命周期管理,避免线程未执行完就被销毁。
下面是一个简单的线程创建示例,使用lambda表达式作为线程执行函数:
#include <iostream>
#include <thread>
int main() {
// 创建线程,执行lambda表达式
std::thread t([]() {
std::cout << "子线程正在执行" << std::endl;
});
// 等待子线程执行完成
t.join();
std::cout << "主线程执行完成" << std::endl;
return 0;
}
std::thread有两个重要的方法:
- join():阻塞当前线程,直到被调用的线程执行完成
- detach():将线程分离,分离后的线程在后台运行,主线程不需要等待它执行完成,但是分离后的线程无法再被join
2. 互斥量std::mutex
多线程同时访问共享数据时会出现数据竞争问题,导致程序运行结果不符合预期。互斥量用于保护共享数据,同一时间只有一个线程可以持有互斥量的锁,其他线程需要等待锁释放才能继续获取锁。
下面是一个使用互斥量保护共享计数器的示例:
#include <iostream>
#include <thread>
#include <mutex>
int shared_count = 0;
std::mutex mtx;
void increment_count() {
for (int i = 0; i < 1000; i++) {
// 获取互斥锁
mtx.lock();
shared_count++;
// 释放互斥锁
mtx.unlock();
}
}
int main() {
std::thread t1(increment_count);
std::thread t2(increment_count);
t1.join();
t2.join();
std::cout << "最终共享计数器的值:" << shared_count << std::endl;
return 0;
}
为了避免忘记释放锁导致死锁,C++11提供了std::lock_guard和std::unique_lock两个RAII风格的锁管理类,它们会在构造时自动获取锁,析构时自动释放锁:
#include <iostream>
#include <thread>
#include <mutex>
int shared_count = 0;
std::mutex mtx;
void increment_count() {
for (int i = 0; i < 1000; i++) {
// 使用lock_guard自动管理锁,作用域结束后自动释放
std::lock_guard<std::mutex> lock(mtx);
shared_count++;
}
}
int main() {
std::thread t1(increment_count);
std::thread t2(increment_count);
t1.join();
t2.join();
std::cout << "最终共享计数器的值:" << shared_count << std::endl;
return 0;
}
3. 条件变量std::condition_variable
条件变量用于线程之间的同步,一个线程等待某个条件成立,另一个线程在条件成立时通知等待的线程。条件变量需要和互斥量配合使用,等待条件时要先获取互斥锁。
下面是一个生产者消费者模型的简单示例,使用条件变量实现线程同步:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
std::queue<int> data_queue;
std::mutex mtx;
std::condition_variable cv;
bool finished = false;
// 生产者线程函数
void producer() {
for (int i = 0; i < 5; i++) {
std::lock_guard<std::mutex> lock(mtx);
data_queue.push(i);
std::cout << "生产者生产数据:" << i << std::endl;
// 通知消费者线程
cv.notify_one();
}
// 生产完成,设置标志
std::lock_guard<std::mutex> lock(mtx);
finished = true;
cv.notify_all();
}
// 消费者线程函数
void consumer() {
while (true) {
std::unique_lock<std::mutex> lock(mtx);
// 等待条件:队列不为空或者生产完成
cv.wait(lock, []() { return !data_queue.empty() || finished; });
// 如果队列为空且生产完成,退出循环
if (data_queue.empty() && finished) {
break;
}
// 消费数据
int data = data_queue.front();
data_queue.pop();
std::cout << "消费者消费数据:" << data << std::endl;
}
}
int main() {
std::thread t1(producer);
std::thread t2(consumer);
t1.join();
t2.join();
std::cout << "生产消费流程结束" << std::endl;
return 0;
}
多线程编程注意事项
- 不要访问已经销毁的线程对象,线程执行完成或者被分离后,线程对象就处于不可连接状态
- 避免死锁,获取多个锁时尽量按照固定的顺序获取,或者使用
std::lock函数同时获取多个锁 - 尽量减少锁的持有时间,只把需要保护的操作放在锁的作用域内,避免锁粒度过大影响性能
- 线程分离后不要尝试访问线程相关的局部变量,因为主线程结束后局部变量会被销毁,分离线程访问会导致未定义行为
常见问题解答
线程创建后忘记调用join或者detach会怎样
如果std::thread对象在析构时还处于可连接状态,程序会调用std::terminate终止运行,因此创建线程后必须调用join或者detach处理线程对象。
条件变量的wait为什么要和循环判断条件配合使用
条件变量的通知可能会被虚假唤醒,即没有线程调用notify也会返回,因此需要在wait返回后再次检查条件是否成立,避免错误执行后续逻辑。上面的示例中使用了wait的第二个参数作为谓词,内部会自动循环检查条件,是更推荐的写法。
C++11多线程编程std_thread互斥量条件变量修改时间:2026-07-03 02:15:31