谁能解释一下((a == 1 && a == 2 && a == 3)== true)?
Can anyone explain how ((a == 1 && a == 2 && a == 3) == true)?
根据输出的信息,任何人都可以解释下面的代码吗?
怎么 (a==1 && a==2 && a==3)
都是真的?
#include <iostream>
#include <thread>
int a = 0;
int main()
{
std::thread runThread([]() { while (true) { a = 1; a = 2; a = 3; }});
while (true)
{
if (a == 1 && a == 2 && a == 3)
{
std::cout << "Hell World!" << std::endl;
}
}
}
输出:
Hell World!
Hell World!
Hell World!
Hell World!
Hell World!
Hell World!
Hell World!
Hell World!
Hell World!
Hell World!
Hell World!
Hell World!
Hell World!
Hell World!
Hell World!
Hell World!
Hell World!
...
2019 年 1 月
我认为这个问题与此高度相关 link -> C++11 introduced a standardized memory model. What does it mean? And how is it going to affect C++ programming?
您可能在禁用优化的情况下编译程序,因此您正在编译的目标体系结构的汇编/机器代码实际上按照它们出现的顺序执行 C++ 抽象机中的所有步骤,包括实际存储或正在加载 to/from RAM。 (调试构建通常将每个变量视为 volatile
。)
在 32 位 int
load/store 自然是原子的典型架构上,调试构建的行为很像一个可移植的 C++ 程序,没有未定义的行为,使用 std::atomic<int> a
和 a.store(1, std::memory_order_relaxed)
(或在 x86 上,std::memory_order_release
)。
程序启动一个线程,重复将值 a 设置为 1、2、3。(这是 运行线程行)。
然后主线程测试a是否等于1,a是否等于2,a是否等于3。如果三个都相等,则打印"hello world"。 (这发生在第二个while(true)
)
之所以打印"hello world"是因为并发。碰巧当一个线程执行三个测试时,另一个线程恰好在正确的时间写入正确的值。记住if
的三部分是一个接一个做的
这在任何地方都无法保证发生。如果您不进行调试构建,则可以对其进行优化。但是考虑到计算机的速度 运行 和线程的 典型 实现,它确实发生了。
不要依赖这种行为。相反,尝试理解两个线程并发执行操作。
您遇到了未定义的行为。
您的代码存在竞争条件;一个线程正在读取 a
而另一个线程正在写入,并且没有发生同步。在 C++ 中不允许这样做。可以编译执行此操作的程序可以执行 任何事情。
事实上,在发布版本中,我希望编译到 if(false)
。编译器优化主线程,发现没有同步,证明没有 UB 不能有 3 个不同的值,并优化掉 if
.
在调试版本中,我可以预料到您看到的症状。不是因为它更正确,而是因为调试版本往往不会遇到那种未定义的行为。
因此,要合理地讨论您的程序,您要做的第一件事就是删除未定义的行为:使 a
成为 std::atomic<int>
而不是 int
。
现在,在发布版和调试版中,您希望看到的...正是您的测试所显示的内容。或无。或者介于两者之间的任何东西。结果不再是未定义的,但它仍然是不确定的。
if
语句不是原子的。条件之间,a
可以变。对于一个程序 运行 永远它应该有时会发生,因为另一个线程正在改变它。
生成的程序定义明确。 Even forward progress guarantees 没问题,因为你读取了一个原子变量。
根据输出的信息,任何人都可以解释下面的代码吗?
怎么 (a==1 && a==2 && a==3)
都是真的?
#include <iostream>
#include <thread>
int a = 0;
int main()
{
std::thread runThread([]() { while (true) { a = 1; a = 2; a = 3; }});
while (true)
{
if (a == 1 && a == 2 && a == 3)
{
std::cout << "Hell World!" << std::endl;
}
}
}
输出:
Hell World! Hell World! Hell World! Hell World! Hell World! Hell World! Hell World! Hell World! Hell World! Hell World! Hell World! Hell World! Hell World! Hell World! Hell World! Hell World! Hell World!
...
2019 年 1 月
我认为这个问题与此高度相关 link -> C++11 introduced a standardized memory model. What does it mean? And how is it going to affect C++ programming?
您可能在禁用优化的情况下编译程序,因此您正在编译的目标体系结构的汇编/机器代码实际上按照它们出现的顺序执行 C++ 抽象机中的所有步骤,包括实际存储或正在加载 to/from RAM。 (调试构建通常将每个变量视为 volatile
。)
在 32 位 int
load/store 自然是原子的典型架构上,调试构建的行为很像一个可移植的 C++ 程序,没有未定义的行为,使用 std::atomic<int> a
和 a.store(1, std::memory_order_relaxed)
(或在 x86 上,std::memory_order_release
)。
程序启动一个线程,重复将值 a 设置为 1、2、3。(这是 运行线程行)。
然后主线程测试a是否等于1,a是否等于2,a是否等于3。如果三个都相等,则打印"hello world"。 (这发生在第二个while(true)
)
之所以打印"hello world"是因为并发。碰巧当一个线程执行三个测试时,另一个线程恰好在正确的时间写入正确的值。记住if
的三部分是一个接一个做的
这在任何地方都无法保证发生。如果您不进行调试构建,则可以对其进行优化。但是考虑到计算机的速度 运行 和线程的 典型 实现,它确实发生了。
不要依赖这种行为。相反,尝试理解两个线程并发执行操作。
您遇到了未定义的行为。
您的代码存在竞争条件;一个线程正在读取 a
而另一个线程正在写入,并且没有发生同步。在 C++ 中不允许这样做。可以编译执行此操作的程序可以执行 任何事情。
事实上,在发布版本中,我希望编译到 if(false)
。编译器优化主线程,发现没有同步,证明没有 UB 不能有 3 个不同的值,并优化掉 if
.
在调试版本中,我可以预料到您看到的症状。不是因为它更正确,而是因为调试版本往往不会遇到那种未定义的行为。
因此,要合理地讨论您的程序,您要做的第一件事就是删除未定义的行为:使 a
成为 std::atomic<int>
而不是 int
。
现在,在发布版和调试版中,您希望看到的...正是您的测试所显示的内容。或无。或者介于两者之间的任何东西。结果不再是未定义的,但它仍然是不确定的。
if
语句不是原子的。条件之间,a
可以变。对于一个程序 运行 永远它应该有时会发生,因为另一个线程正在改变它。
生成的程序定义明确。 Even forward progress guarantees 没问题,因为你读取了一个原子变量。