c++ - 代码重新排序会影响我的测试吗

标签 c++ exception try-catch compiler-optimization

我正在为一个类编写单元测试,以在没有可用内存时测试插入。它依赖于 nbElementInsertedinsert_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 是一个函数,该函数的所有副作用都应该在转到下一行之前完成。 throw 是一种副作用。

奖励点:如果正确答案是“是的,可能会发生重新排序”,那么两行之间的内存屏障是否足以修复它?

最佳答案

没有。重新排序仅在多线程或多处理场景中发挥作用。在单线程中,编译器无法以改变程序行为的方式重新排序指令。异常(exception)情况也不异常(exception)。

当两个线程读写共享状态时,重新排序变得可见。如果线程 A 对共享变量进行了修改,线程 B 可以乱序看到这些修改,如果它缓存了共享状态,甚至根本看不到。这可能是由于线程 A 或线程 B 或两者的优化所致。

不过,线程 A 总是会按顺序看到自己的修改。每个sequence point必须按顺序发生,至少就本地线程而言是这样。

假设线程 A 执行了这段代码:

a = foo() + bar();
b = baz;

每个;引入一个序列点。允许编译器首先调用 foo()bar(),无论哪个,因为 + 不引入序列点。如果您放置打印输出,您可能会看到 foo() 首先被调用,或者您可能会看到 bar() 首先被调用。任何一个都是正确的。不过,它必须在将 baz 分配给 b 之前调用它们。如果 foo()bar() 抛出异常 b 必须保留其现有值。

但是,如果编译器知道 foo()bar() 永远不会抛出,并且它们的执行绝不会依赖于 b< 的值,它可以重新排序这两个语句。这将是一个有效的优化。线程 A 无法知道语句已重新排序。

另一方面,线程 B 会知道。多线程编程中的问题是序列点不适用于其他线程。这就是内存屏障的用武之地。从某种意义上说,内存屏障是跨线程序列点。

关于c++ - 代码重新排序会影响我的测试吗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17494872/

相关文章:

c++ - 在 WebKit 中禁用滚动条(平面框架模式)

c++ - 为什么 std::initializer_list 不是内置语言?

c# - ASP.Net MVC - 如何处理 JSON 操作中的异常(返回 JSON 错误信息),同时发布过滤器的异常?

java - 何时记录链式异常?

c# - 在 C# 中将超出范围的数字转换为枚举不会产生异常

c++ - 为什么 std::map 重载运算符 < 不使用比较

c++ - 使用 URL 的 ShellExecute 会产生无关的错误消息。缺少哪个文件关联?

java - 具有多个 catch 语句的无法访问的代码

java - try-catch block 有必要吗?

node.js - 无法理解为什么 try and catch 在 mongoose 中没有按预期工作