一、定义
1.普通变量
int、bool、double、自定义变量
读写是拆分多条CPU微指令,不是一次性完成。
2.原子变量
std::atomic、QAtomicInteger、QAtomicBoolean
硬件层级一次性完整读写,中途不会被其他线程打断。
二、核心区别
1、执行指令
- 普通变量
赋值/自增是多步指令,例: a++
1)从内存读a到CPU
2)CPU计算+1
3)写回内存
多线程会穿插插队,数据覆盖错乱。
- 原子变量
a++ 整条指令不可拆分,执行中其他线程强制阻塞,不会插队。
2、多线程安全
- 普通变量:多线程同时读写=数据竞争、脏数据、程序崩溃
- 原子变量:天生线程安全,无需加锁
3、内存排序(指令重排)
- 普通变量:编译器/CPU会乱序优化指令,多线程逻辑错乱
- 原子变量:禁止指令重排,执行顺序固定
4、性能
1)普通变量:速度最快,无任何限制
2)原子变量:比普通慢一点、比mutex锁快非常多
5、使用范围
-
普通变量:所有类型、结构体、字符串、对象都能用
-
原子变量:只支持int、bool、long基础简单类型,结构体不可用
三、联系
1.本质都是内存存放的数据,占用内存方式一致。
2.原子变量是给普通变量加硬件防护buff。
3.都是用来存数值、状态标记。
速度:普通变量>原子变量>互斥锁mutex
安全:mutex>原子变量>普通变量
四、使用场景划分
1.单纯状态标记、开关、计数、循环标志
👉用原子变量,无锁高效
2.字符串、结构体、多步复杂赋值
👉普通变量+QMutex互斥锁
3.单线程所有变量全部用普通变量,无区别。
五 结构体变量多个线程的互斥操作
添加头文件 #include <QMutex>
// 复杂结构体互斥示例
struct MyData {
int a;
QString s; // 非平凡拷贝
};
MyData shared_data;
QMutex data_mutex; // 保护锁
void thread_safe_write() {
QMutexLocker locker(&data_mutex); // 自动加锁/解锁
shared_data.a = 20;
shared_data.s = "hello";
}
void thread_safe_read() {
QMutexLocker locker(&data_mutex);
qDebug() << shared_data.a << shared_data.s;
}
复杂结构体(含QString/指针) 一般采用 QMutex + QMutexLocker组合使用(安全、通用)。
注意:不需要为每个线程单独定义QMutex。
1)锁是保护【共享数据】的,不是保护【线程】的。
2) 一份共享数据 → 只需要一把锁。
3.)所有访问这份数据的线程,都共用这一把锁。