0

众所周知,编译器或 CPU 可以根据需要重新排序执行,前提是它们遵循 as-if 规则。例如,如果我们有这样一段代码:

C = A + B;
D = E + F;

编译器或 CPU 可能会D = E + FC = A + B. 我可以理解。

现在让我们谈谈另一个案例。

说我有两个线程ab. 我想在执行时设置一些标记,以便我可以监控和的整个a过程b

queue q; // thread safe

void thread_a()
{
    // do something
    q.push("a - 1");
    // do something
    q.push("a - 2");
}

void thread_b()
{
    // do something
    q.push("b - 1");
    // do something
    q.push("b - 2");
}

我的问题是:既然我们有 as-if 规则并且执行顺序可能会重新排序,是否意味着其中的消息q不可靠?意思是真正的执行顺序是a - 1, b - 1,但其中可能有, ,b - 2和? 如果可能发生这种情况,我应该如何设计或使用哪种技术来监控多线程进程?a - 2qa - 1a - 2b - 1b - 2

4

1 回答 1

1

重新排序和多线程是两个不同的东西:

通过多线程,可能的输出是:

  • "a - 1", "a - 2", "b - 1","b - 2"
  • "a - 1", "b - 1", "a - 2","b - 2"
  • "a - 1", "b - 1", "b - 2","a - 2"
  • "b - 1", "b - 2", "a - 1","a - 2"
  • "b - 1", "a - 1", "b - 2","a - 2"
  • "b - 1", "a - 1", "a - 2","b - 2"

您只需保证“a - 1”在“a - 2”之前,“b - 1”在“b - 2”之前。(与重新排序无关)

使用 as-if 规则重新排序只是一种优化。

as_if状态:

只要满足以下条件,C++ 编译器就可以对程序执行任何更改:

  1. 对 volatile 对象的访问(读取和写入)严格按照它们出现的表达式的语义进行。特别是,它们不会针对同一线程上的其他易失性访问重新排序。(C++11 起)
  2. 在程序终止时,写入文件的数据与程序执行时完全一样。
  3. 发送到交互式设备的提示文本将在程序等待输入之前显示。
  4. 如果支持 ISO C pragma #pragma STDC FENV_ACCESS 并将其设置为 ON,则浮点算术运算符和函数调用可以保证观察到对浮点环境的更改(浮点异常和舍入模式):如果按书面方式执行,除了强制转换和赋值以外的任何浮点表达式的结果可能具有与表达式类型不同的浮点类型的范围和精度(参见 FLT_EVAL_METHOD),尽管有上述规定,任何中间结果浮点表达式可以计算为无限范围和精度(除非#pragma STDC FP_CONTRACT 为OFF)

您的代码(除了可能的// do something)什么都不做,因此它甚至可以完全删除 2 代码,按下“c - 1”。

但是如果在打印队列内容之后,那么内容应该是上面显示的 6 个之一。

于 2021-03-24T10:23:52.123 回答