我迷路了。我想利用编译器资源管理器来实验多线程C代码,并从一段简单的代码开始。代码是用-O3编译的。
static int hang = 0;
void set_hang(int x) {
hang = x;
}
void wait() {
while (hang != 0) {
// wait...
}
}令我惊讶的是,这是编译器的输出:
set_hang(int):
mov dword ptr [rip + hang], edi
ret
wait():
ret我花了一段时间才注意到,我正在以C++而不是C的形式编译代码。切换到C给了我一些我所期望的东西:
set_hang:
mov DWORD PTR hang[rip], edi
ret
wait:
mov eax, DWORD PTR hang[rip]
test eax, eax
je .L3
.L5:
jmp .L5
.L3:
ret因此,当编译为C++时,wait()总是返回,不管之前传递给set_hang()的是哪个值。我通过编译和我的电脑上的代码来确认这一点。此代码立即存在,而我希望它会提前挂起:
int main(void) {
set_hang(1);
wait();
return 0;
} 事实上,如果我用gcc而不是g++编译它,它就挂起了。
我用不同的编译器(Clang和GCC)进行了实验,而这种情况只发生在Clang 12.0.0或higer或GCC 10.1或以上。如果我也通过了--std=c++98,我所期望的代码也会发出,所以它似乎是特定于C++11和更高级别的代码。
从static中删除hang关键字不会影响发出的程序集。
这里发生了什么事?我写C++已经有几个月了,所以我可能错过了一些关于最新最棒的C++黑魔法的知识,但这是非常简单的代码。我太笨了。
编辑:甚至这个程序也被完全优化了:
// test.cpp
static int hang = 0;
static void set_hang(int x) {
hang = x;
}
static void wait() {
while (hang != 0) {
// wait...
}
}
int main(void) {
set_hang(1);
wait();
return 0;
}编译器输出:
main:
xor eax, eax
retGCC版10.3.0关于Ubuntu:
此命令将挂起:g++ -O1 -o test test.cpp && ./test
这个命令不会:g++ -O2 -o test test.cpp && ./test
发布于 2021-12-28 12:48:54
这是因为下面的规则:
intro.progress 该实现可能假定任何线程最终都将执行以下操作之一:
编译器能够证明一个进入循环的程序永远不会做任何列出的事情,因此它被允许假设循环永远不会被输入。
https://stackoverflow.com/questions/70506857
复制相似问题