现象: gdb bt 卡在 spinlock_unlock() 位置。

  1. 查了半天代码,我的每一个锁都没有问题。给我看吐血了。

  2. 最后没辙了灵机一动 gdb disassemble 发现这里死循环了:

gdb disassemble

原来是一个标志位没有设置为 volatile ,代码被优化了。大概的代码如下:

while (true) {
    // 多线程中可以被修改的一个标志
    if (flags_1 == STATUS_1) { 
        continue
    }
    // 其他逻辑
    // ... ...
}

但是为什么不是必现的 BUG 呢? AI 给了一堆解释,但是没怎么看懂。

举报· 1346 次点击
登录 注册 站外分享
12 条回复  
chenyu0x00 初学 3 天前
这个不是多线程的 bug ,这个是 C/C++编译器的"特性"。 相当于有这样一段代码: ```c++ int flag; while (flag == 0) { } ``` 编译器在不进行优化(-O0)的情况下,每次 while 循环都会从内存中读 flag 的值,并和 0 进行判断。 当使用了编译器优化的情况下,编译器就会发现"这个程序员真 SB ,为什么每次都要从内存中读 flag 的值呢,我直接读一次,放到寄存器里面,之后访问速度就更快了,判断也可以优化成一次",于是代码就变成这样了: ```c++ register eax = flag; if (eax == 0) { while (true) { } } ``` 你会发现这个优化在单线程的情况下是完全没有问题的,在多线程情况下就出问题了。 而使用 volatile int flag 就是告诉编译器"不要偷懒,我让你从内存读 flag 你就从内存读,让你写到内存就写到内存"。 不过如上面所说,建议多线程通信使用 atomic ,因为 atomic 还解决了多线程情况下的内存序的问题。
w568w 小成 3 天前
推荐阅读: https://davekilian.com/acquire-release.html
mmdsun 小成 3 天前
C 语言多线程经典 BUG 了。 让 ai 写一个 c 语言多线程自旋代码吧。不用原子锁条件变量肯定爆炸
yyysuo 初学 3 天前
@qzhai 大家都不怎么服气的。
PTLin 小成 3 天前
@PTLin 甚至在一些情况下,编译器发现你后续代码没用操作这个变量,虽然你这个变量的操作是在其他线程,但是编译器并不知道这些信息,因为你没用同步手段,编译器可能会激进的吧你这个判断删除。
ccpp132 小成 3 天前
c++的话 volatile 也不算对,应该用 atomic ,这点和 java 还不是一回事
wfg 初学 3 天前
你贴的代码,不管有没有 continue 不都是继续循环吗?
PTLin 小成 3 天前
简单来说就是你没用任何同步手段,例如原子变量,内存屏障,volatile 。你这种情况下有可能会遇到 指令重排,例如把你这个判断的代码重排到后面。 从缓存中读取,例如把你这个 flags 放到寄存器里,然后从寄存器里读出。 操作拆分,例如把你这个读取操作在汇编的实现中拆分成两次内存操作。 相关的东西你还是去了解下内存序什么的吧。
qzhai 小成 3 天前
分享一个死循环给我?我写死循环的经验可是多得很
12下一页
返回顶部