在C++框架的开发过程中,线程和并发处理能力直接决定了程序在多核CPU环境下的运行效率。C++11标准之后,标准库原生提供了完整的线程和并发支持,不需要再依赖平台特定的线程库,这大大降低了跨平台开发的难度。

C++线程的基础使用
C++标准库中的<thread>头文件提供了线程相关的核心功能,我们可以通过创建std::thread对象来启动一个新的线程。线程执行的函数可以是普通函数、lambda表达式或者类的成员函数。
下面是一个简单的线程创建示例:
#include <iostream>
#include <thread>
// 普通函数作为线程执行体
void print_task(int num) {
std::cout << "线程执行任务,参数值为:" << num << std::endl;
}
int main() {
// 创建线程,传入函数和参数
std::thread t(print_task, 10);
// 等待线程执行完成
t.join();
// 也可以使用detach让线程后台运行,但是要注意生命周期问题
// std::thread t2(print_task, 20);
// t2.detach();
return 0;
}
需要注意的是,std::thread对象在销毁前必须调用join()或者detach(),否则程序会抛出异常。如果调用detach(),线程会在后台独立运行,这时候要确保线程访问的变量生命周期长于线程本身,避免出现悬垂引用。
并发场景下的同步工具
多个线程同时访问共享资源时,很容易出现数据竞争问题,这时候就需要使用同步工具来保证数据的一致性。C++标准库提供了多种同步工具,最常用的是互斥锁和条件变量。
互斥锁的使用
互斥锁(std::mutex)用来保护共享资源,同一时间只有一个线程可以持有锁,其他线程需要等待锁释放才能继续获取。为了防止忘记释放锁导致死锁,通常会配合std::lock_guard或者std::unique_lock使用,这两个RAII类会在析构时自动释放锁。
下面是一个使用互斥锁保护共享计数器的示例:
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
int shared_counter = 0;
std::mutex counter_mutex;
void increment_counter(int times) {
for (int i = 0; i < times; ++i) {
// 自动加锁,作用域结束后自动释放
std::lock_guard<std::mutex> lock(counter_mutex);
++shared_counter;
}
}
int main() {
std::vector<std::thread> threads;
// 创建5个线程,每个线程累加1000次
for (int i = 0; i < 5; ++i) {
threads.emplace_back(increment_counter, 1000);
}
// 等待所有线程完成
for (auto& t : threads) {
t.join();
}
std::cout << "最终计数器值:" << shared_counter << std::endl;
return 0;
}
条件变量的使用
条件变量(std::condition_variable)用来实现线程之间的通知机制,一个线程可以等待某个条件满足,另一个线程在条件满足时通知等待的线程。条件变量需要和互斥锁配合使用,等待的时候会自动释放锁,被唤醒后会重新获取锁。
下面是一个生产者消费者模型的简单示例:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
std::queue<int> task_queue;
std::mutex queue_mutex;
std::condition_variable queue_cv;
bool is_producing = true;
// 生产者线程
void producer() {
for (int i = 0; i < 10; ++i) {
std::lock_guard<std::mutex> lock(queue_mutex);
task_queue.push(i);
std::cout << "生产任务:" << i << std::endl;
// 通知消费者线程
queue_cv.notify_one();
}
// 生产结束,通知所有消费者
is_producing = false;
queue_cv.notify_all();
}
// 消费者线程
void consumer(int id) {
while (true) {
std::unique_lock<std::mutex> lock(queue_mutex);
// 等待队列不为空或者生产结束
queue_cv.wait(lock, []() {
return !task_queue.empty() || !is_producing;
});
// 如果队列为空且生产结束,退出循环
if (task_queue.empty() && !is_producing) {
break;
}
// 取出任务执行
int task = task_queue.front();
task_queue.pop();
lock.unlock(); // 提前释放锁,减少锁持有时间
std::cout << "消费者" << id << "处理任务:" << task << std::endl;
}
}
int main() {
std::thread prod(producer);
std::thread cons1(consumer, 1);
std::thread cons2(consumer, 2);
prod.join();
cons1.join();
cons2.join();
return 0;
}
框架中常用的线程池实现
在实际的C++框架中,频繁创建和销毁线程会带来较大的性能开销,因此通常会使用线程池来管理线程。线程池会预先创建一定数量的线程,复用这些线程来执行提交的任务,减少线程创建销毁的成本。
一个简单的线程池核心实现如下:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <vector>
#include <functional>
#include <memory>
class ThreadPool {
public:
// 构造函数,初始化线程数量
ThreadPool(size_t thread_num) : stop(false) {
for (size_t i = 0; i < thread_num; ++i) {
workers.emplace_back([this]() {
while (true) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(queue_mutex);
// 等待任务或者停止信号
condition.wait(lock, [this]() {
return stop || !tasks.empty();
});
// 如果停止且任务队列为空,退出线程
if (stop && tasks.empty()) {
return;
}
// 取出任务
task = std::move(tasks.front());
tasks.pop();
}
// 执行任务
task();
}
});
}
}
// 提交任务到线程池
template<class F, class... Args>
void enqueue(F&& f, Args&&... args) {
{
std::unique_lock<std::mutex> lock(queue_mutex);
// 停止状态下不允许提交任务
if (stop) {
throw std::runtime_error("线程池已停止,无法提交任务");
}
// 将任务和参数绑定成可调用对象
tasks.emplace(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
}
// 通知一个等待的线程
condition.notify_one();
}
// 析构函数,停止所有线程
~ThreadPool() {
{
std::unique_lock<std::mutex> lock(queue_mutex);
stop = true;
}
condition.notify_all();
for (auto& worker : workers) {
if (worker.joinable()) {
worker.join();
}
}
}
private:
std::vector<std::thread> workers; // 工作线程集合
std::queue<std::function<void()>> tasks; // 任务队列
std::mutex queue_mutex; // 队列互斥锁
std::condition_variable condition; // 条件变量
bool stop; // 停止标志
};
// 测试线程池
void test_task(int id) {
std::cout << "执行任务:" << id << ",线程ID:" << std::this_thread::get_id() << std::endl;
}
int main() {
// 创建包含4个线程的线程池
ThreadPool pool(4);
// 提交10个任务
for (int i = 0; i < 10; ++i) {
pool.enqueue(test_task, i);
}
// 主线程等待,确保任务执行完成
std::this_thread::sleep_for(std::chrono::seconds(2));
return 0;
}
并发处理的常见优化建议
在C++框架中做并发优化时,可以参考以下几点:
- 尽量减少锁的持有时间,锁的范围越小越好,避免把无关的操作放在锁内部。
- 优先使用读写锁(std::shared_mutex)来处理读多写少的场景,多个读线程可以同时持有读锁,提升并发度。
- 避免死锁,多个锁的获取顺序要统一,或者使用std::lock同时获取多个锁。
- 线程数量不要设置过多,一般设置为CPU核心数的1到2倍比较合适,过多的线程会导致上下文切换开销增大。
- 无锁数据结构适合高并发场景,但是实现难度较大,需要谨慎使用,避免引入隐藏的bug。
通过合理使用C++提供的线程和并发工具,结合业务场景做针对性的优化,就可以在C++框架中实现高效稳定的并发处理能力,充分发挥多核CPU的性能优势。
C++_thread并发编程互斥锁条件变量线程池修改时间:2026-07-04 04:36:37