有一个变量 在有些线程没有加锁 有些线程加锁了,那我在这些加锁的线程中能起到对应的作用吗
这是一个非常经典、但也很危险的问题。
🧨 简单结论:
如果一个变量在某些线程访问时没有加锁,即使其他线程对它加了锁,也:
❌ 不能保证线程安全!
❌ 加锁的部分不会“保护”未加锁的部分!
🔍 为什么?(原理讲解)
锁的本质是线程之间的同步原语,它的工作机制依赖于所有访问共享资源的线程都遵守加锁协议。
假设:
int shared_var = 0;
std::mutex mtx;
// Thread A(加锁访问)
void safe_write() {
std::lock_guard<std::mutex> lock(mtx);
shared_var = 1;
}
// Thread B(没加锁访问)
void unsafe_read() {
int val = shared_var; // 没加锁
std::cout << val << std::endl;
}
会发生什么?
-
线程 B 并没有使用 mutex,它访问了
shared_var
。 -
编译器和 CPU 根本不知道你“逻辑上想保护”这个变量。
-
CPU 可能重排指令,导致变量状态不同步。
-
在某些架构(比如 x86 之外)上,甚至可能读到完全未定义的值。
-
数据竞争行为是 undefined behavior(未定义行为),哪怕在调试时看似“没事”。
✅ 正确做法:所有访问共享资源的地方都必须统一加锁
void safe_read() {
std::lock_guard<std::mutex> lock(mtx);
int val = shared_var;
std::cout << val << std::endl;
}
🚨 锁的“保护范围”必须靠人为维护
🔑 加锁不是对变量加的锁,而是对代码执行的保护!
如果一部分代码用了锁,一部分没用,那锁就像一扇半开的门,根本起不到隔离和同步作用。
👀 补充:用 std::atomic
替代锁的情况
如果你只对单个变量进行简单的读写操作(比如 int
类型),可以考虑使用 std::atomic<int>
,它是无锁线程安全的。
#include <atomic>
std::atomic<int> shared_var{0};
void write() {
shared_var.store(1);
}
void read() {
int val = shared_var.load();
}
但如果你有多个变量要一起修改,或复杂操作(比如 ++、列表插入等),就还是需要 std::mutex
。
🧠 总结
-
锁只有在所有访问者都遵守的情况下才有意义。
-
有加锁和没加锁混用 = 数据竞争 = undefined behavior。
-
最好制定清晰的访问协议:谁、什么时机、用什么锁访问。
-
对简单原子变量,可考虑
std::atomic
。