代码重新排序会影响我的测试吗
Can code reordering affect my test
我正在为一个类编写一个单元测试,以便在没有可用内存的情况下测试插入。它依赖于nbElementInserted
在insert_edge
返回后递增的事实。
void test()
{
adjacency_list a(true);
MemoryVacuum no_memory_after_this_line;
bool signalReceived = false;
size_t nbElementInserted = 0;
do
{
try
{
a.insert_edge( 0, 1, true ); // this should throw
nbElementInserted++;
}
catch(std::bad_alloc &)
{
signalReceived = true;
}
}
while (!signalReceived); // this loop is necessary because the
// memory vacuum only prevents new memory
// pages from being mapped. so the first
// allocations may succeed.
CHECK_EQUAL( nbElementInserted, a.nb_edges() );
}
现在我想知道这两种说法中哪一种是真的:
- 可以进行重新排序,在这种情况下,
nbElementInserted
可以在insert_edge
引发异常之前递增,这将使我的情况无效。重新排序可能发生,因为如果两行被排列,用户的可见结果是相同的 - 重新排序不能发生,因为
insert_edge
是一个函数,在转到下一行之前应该完成该函数的所有副作用。投掷是一种副作用
加分:如果正确答案是"是的,可以重新排序",那么两行之间的内存屏障是否足以修复它?
否。重新排序只在多线程或多处理场景中发挥作用。在单个线程中,编译器不能以改变程序行为的方式对指令进行重新排序。例外情况不属于此规则的例外情况。
当两个线程读写到共享状态时,可以看到重新排序。如果线程A对共享变量进行了修改,那么线程B可能会看到这些无序的修改,甚至在缓存了共享状态的情况下根本看不到。这可能是由于线程A或线程B或两者中的优化。
线程A总是按顺序看到自己的修改。每个序列点必须按顺序发生,至少就本地线程所知是这样。
假设线程A执行了以下代码:
a = foo() + bar();
b = baz;
每个;
引入一个序列点。编译器可以先调用foo()
或bar()
,不管它喜欢什么,因为+
不引入序列点。如果打印输出,您可能会看到先调用foo()
,也可能会看到首先调用bar()
。任何一个都是正确的。不过,在将baz
分配给b
之前,它必须调用它们。如果foo()
或bar()
抛出异常,则b
必须保留其现有值。
然而,如果编译器知道foo()
和bar()
从不抛出,并且它们的执行在任何方面都不取决于b
的值,那么它可以重新排序这两个语句。这将是一个有效的优化。线程A将无法知道语句已被重新排序。
另一方面,线程B会知道。多线程编程的问题是序列点不适用于其他线程。这就是内存屏障的作用。从某种意义上说,内存屏障是跨线程序列的点。
相关文章:
- 我的神经网络不起作用 [XOR 问题]
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 我的字符计数代码计算错误.为什么
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- cmake在我的项目中所需的所有静态库都不成功
- 为什么我的代码在输出中增加了93天
- 我的简单if-else语句是如何无法访问的代码
- 为什么我的for循环不能正确获取argv
- 我的项目不会像"undefined reference to `grpc::g_core_codegen_interface'"那样使用未定义的引用错误进行编译
- 0-1背包代码中的错误.我的代码中有什么错误
- 当我的阵列太大时出现分段错误
- 如何确认我的constexpr表达式实际上已经在编译时执行
- 为什么二进制搜索在我的测试中不起作用
- 使用"静态"如何影响我的代码速度?
- 额外的反斜杠字符不会影响我的程序.为什么
- 这些continue语句如何影响我的代码
- 我认为这是一个编译器错误,这不应该影响我的代码,但它是
- 代码重新排序会影响我的测试吗
- 我可以在不影响性能的情况下将此宏更改为内联函数吗
- 我正在更改我的代码,但编译的程序不受影响