🚀C++多线程编程实战指南:4种典型方案深度解析
还在为多线程数据竞争和死锁问题头疼?本文通过4个真实代码示例,深度剖析:
- 🔥 原子操作的无锁编程技巧
- 🔒 互斥锁的最佳使用姿势
- ⚡ Qt线程方案的工程实践
- 🚀 moveToThread的高效应用场景

目录
📑 1 实现方案
1️⃣ 使用原子控制保存数据
示例代码:
class Data : public std::enable_shared_from_this<Data> {
public:
Data() { startWorkerThread(); }
~Data() { stopWorkerThread(); }
private:
class Worker;
std::unique_ptr<Worker> m_worker;
std::atomic<int> data{0};
void startWorkerThread() {
if(m_worker)
return;
m_worker = std::make_unique<Worker>(shared_from_this());
// 启动线程
m_worker->start();
}
void stopWorkerThread() {
if (m_worker) {
m_worker->stop();
m_worker.reset();
}
}
};
class Data::Worker {
public:
Worker(std::shared_ptr<Data> data){
m_data = data;
}
~Woker(){}
void start(){
m_stop = false;
if(m_thread.joinable()) {
m_thread.join();
}
m_thread = std::thread([this] { run(); });
}
void stop(){
m_stop = true;
if(m_thread.joinable()) {
m_thread.join();
}
}
private:
std::atomic<bool> m_stop{false};
std::thread m_thread;
std::weak_ptr <Data> m_data; // 使用弱指针,避免循环引用
void run() {
while(!m_stop){
auto data_ptr = m_data.lock();
if(!data_ptr) {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
continue;
}
int data = m_data->data.load(std::memory_order_acquire);
if (data > 0) {
auto temp = data * 3 / 2;
m_data->data.store(temp, std::memory_order_release);
}
std::this_thread::sleep_for(std::chrono::milliseconds(2));
}
}
};
// 用户必须通过 shared_ptr 创建 Data 对象
auto data = std::make_shared<Data>();
2️⃣ 使用互斥锁保护数据
示例代码:
#include <mutex>
#include <thread>
class Data {
public:
void decrement() {
std::lock_guard<std::mutex> lock(m_mutex);
if (data > 0) data--;
}
int get() const {
std::lock_guard<std::mutex> lock(m_mutex);
return data;
}
private:
mutable std::mutex m_mutex;
int data = 0;
};
class Worker {
public:
explicit Worker(std::shared_ptr<Data> data) : m_data(data), m_stop(false) {}
void start() {
m_thread = std::thread([this] {
while (!m_stop.load(std::memory_order_acquire)) {
m_data.decrement();
std::this_thread::sleep_for(std::chrono::milliseconds(2));
}
});
}
void stop() {
m_stop.store(true, std::memory_order_release);
if (m_thread.joinable()) m_thread.join();
}
private:
std::weak_ptr<Data> m_data; // 使用弱指针,避免循环引用
std::atomic<bool> m_stop;
std::thread m_thread;
};
int main(){
std::shared_ptr<Data> data = std::make_shared<Data>();
Worker worker(data);
worker.start();
std::this_thread::sleep_for(std::chrono::seconds(5));
worker.stop();
return 0;
}
3️⃣ 使用QThread
示例代码:
#include <QAtomicInteger>
class Data {
public:
Data() : m_total(0), m_count(0) {}
void calculate(int value) {
m_total.fetchAndAddOrdered(value); // 原子加法
m_count.fetchAndAddOrdered(1); // 原子递增
}
int getAverage() const {
const int count = m_count.loadAcquire();
const int total = m_total.loadAcquire();
return (count == 0) ? 0 : total / count;
}
private:
QAtomicInt m_total; // 总和
QAtomicInt m_count; // 计数
};
class Worker : public QThread {
Q_OBJECT
public:
// 通过智能指针管理Data所有权
explicit Worker(QPointer<Data> data, QObject* parent = nullptr)
: QThread(parent), m_data(data), m_stop(false) {}
void stop() {
m_stop = true;
if (isRunning()) {
quit();
wait(); // 等待线程结束
}
}
signals:
void averageUpdated(int value);
protected:
void run() override {
QRandomGenerator rand(QTime::currentTime().msec());
while (!m_stop) {
// 检查Data指针有效性
if (m_data.isNull()) break;
// 更新数据并通知
const int num = rand.bounded(1, 100);
m_data->calculate(num);
emit averageUpdated(m_data->getAverage());
QThread::msleep(100);
}
}
private:
QPointer<Data> m_data; // 共享数据指针
QAtomicInteger<bool> m_stop{false};
};
int main(){
QPointer<Data> data = new Data();
// 启动工作线程
Worker worker(data);
QObject::connect(&worker, &Worker::averageUpdated, [](int avg) { qDebug() << "Current average:" << avg; });
worker.start();
// 运行5秒后停止
QTimer::singleShot(5000, [&worker] {
worker.stop();
});
return 0;
}
4️⃣ 使用moveToThread
示例代码:
class Data {
public:
void calculate(int value) {
QMutexLocker locker(&m_mutex);
m_total += value;
m_count++;
}
int getAverage() const {
QMutexLocker locker(&m_mutex);
return (m_count == 0) ? 0 : m_total / m_count;
}
private:
mutable QMutex m_mutex; // 允许const方法加锁
int m_total = 0;
int m_count = 0;
};
class Worker : public QObject {
Q_OBJECT
public:
explicit Worker(QPointer<Data> data, QObject* parent = nullptr) : QObject(parent), m_data(data) {}
void start() {
QRandomGenerator rand;
while (!m_stop) {
// 检查指针有效性
if (!m_data) break;
// 更新数据并通知
const int num = rand.bounded(1, 100);
m_data->calculate(num);
emit averageUpdated(m_data->getAverage());
QThread::msleep(100);
}
emit workFinished();
}
void stop() {
m_stop = true;
}
signals:
void averageUpdated(int value);
void workFinished();
private:
QPointer<Data> m_data;
std::atomic<bool> m_stop{false};
};
int main(){
QThread thread = new QThread();
QPointer<Data> data = QPointer<Data>(new Data());
Worker worker(data);
worker.moveToThread(thread);
QObject::connect(thread, &QThread::finished, [thread] {
thread->quit();
thread->deleteLater();
});
QObject::connect(thread, &QThread::started, [worker] {
worker.start();
});
QObject::connect(&worker, &Worker::averageUpdated, [](int avg) { qDebug() << "Current average:" << avg; });
QObject::connect(&worker, &Worker::workFinished, [thread] { thread->quit(); });
// 启动线程
thread->start();
// 运行5秒后停止
QTimer::singleShot(5000, [&worker] {
worker.stop();
worker.quit();
worker.wait();
});
return 0;
};
🔎 2 方案对比
1. 原子控制保存数据(无锁编程)
优点:
- 性能高效:原子操作无锁,适用于高频读写场景
- 轻量级:适合简单数据类型(int/bool等)
- 内存序控制:可通过memory_order精细优化
缺点:
- 适用性有限:仅适用于简单数据类型
- 逻辑复杂度高:需要严格设计内存访问顺序
- 容易出错:自旋等待可能消耗CPU资源
适用场景:
- 高性能计数器(如实时统计)
- 状态标志位的快速更新
- 无锁数据结构的实现
2. 互斥锁保护数据
优点:
- 通用性强:适合保护复杂数据结构
- 线程安全:确保临界区操作原子性
- 开发简单:标准库支持,容易实现
缺点:
- 性能开销:锁竞争会导致上下文切换
- 死锁风险:需要仔细设计锁的获取顺序
- 粒度控制:粗粒度锁可能降低并发性
适用场景:
- 需要保护复杂对象状态(如容器类)
- 对数据一致性要求严格的场景
- 需要跨多个变量保持原子性的操作
3. 使用QThread(继承方式)
优点:
- Qt原生支持:与信号槽机制深度整合
- 生命周期明确:通过start()/quit()管理线程
- 资源管理方便:可搭配QSharedPointer使用
缺点:
- 继承限制:必须继承QThread类
- 灵活性不足:run()函数是单一入口点
- 内存管理:需要手动处理跨线程对象
适用场景:
- Qt GUI应用程序的后台任务
- 需要与界面线程频繁交互的场景
- 已深度使用Qt框架的项目
4. 使用moveToThread(工作对象模式)
优点:
- 解耦设计:业务逻辑与线程控制分离
- 事件驱动:可利用Qt事件循环
- 资源复用:单个线程处理多个任务
缺点:
- 学习曲线:需要理解Qt对象树机制
- 信号槽开销:跨线程通信存在性能损耗
- 调试困难:异常传播路径不直观
适用场景:
- 需要长期运行的后台服务
- 事件驱动型任务(如网络通信)
- 需要动态创建/销毁任务的系统
🎨 3 方案选择建议
特征需求 | 推荐方案 |
---|---|
超高频计数器更新 | 原子控制 |
复杂数据结构保护 | 互斥锁 |
Qt GUI程序后台计算 | QThread |
事件驱动的异步任务 | moveToThread |
跨平台通用逻辑 | 原子控制/互斥锁 |
需要精细控制内存顺序 | 原子控制(memory_order) |
需要与界面元素频繁交互 | QThread/moveToThread |