C++ 在这种情况下,编译器可以根据自己的意愿对指令重新排序

C++ 在这种情况下,编译器可以根据自己的意愿对指令重新排序,c++,multithreading,c++11,C++,Multithreading,C++11,在哪些情况下,编译器可以根据自己的意愿对指令重新排序 例如,在涉及诸如互斥体之类的同步原语的情况下,它们是否可以重新排序,如以下示例所示: void foo() { int x = 0; { std::lock_guard<std::mutex> lock(g_mutex); std::cout << x << std::endl; } x = 1; } 若然,原因为何?它在哪里写的?不,不能。互斥体的一个显著特征是代码重新排

在哪些情况下,编译器可以根据自己的意愿对指令重新排序

例如,在涉及诸如互斥体之类的同步原语的情况下,它们是否可以重新排序,如以下示例所示:

void foo()
{
  int x = 0;
  {
    std::lock_guard<std::mutex> lock(g_mutex);
    std::cout << x << std::endl;
  }
  x = 1;
}

若然,原因为何?它在哪里写的?

不,不能。互斥体的一个显著特征是代码重新排序不会跨越互斥体的获取或释放

在一个旁注中,临界区不是POSIX模型中的同步原语(C++线程的内容主要基于它)。相反,它是一个逻辑术语,意味着必须保护的代码段

编辑

回答第二个问题

是的,如果线程1首先获得互斥锁,则打印的值将为1。这种明确保证的原因是互斥低级别代码和该代码的硬件实现的结合。虽然没有说明,但我假设两段代码属于两个不同的函数(为了简单起见)。请注意,在这种情况下,无论互斥量如何,都不会进行编译器优化-有两个独立的函数,编译器优化是函数的局部优化


在互斥体级别上,互斥体的任何实现都将包括一条直接或间接指令,用于在获取互斥体之前和之后放置内存围栏。这些说明将指示hardwre刷新其所有缓存,因此不会使用缓存值。

不,它不能。互斥体的一个显著特征是代码重新排序不会跨越互斥体的获取或释放

在一个旁注中,临界区不是POSIX模型中的同步原语(C++线程的内容主要基于它)。相反,它是一个逻辑术语,意味着必须保护的代码段

编辑

回答第二个问题

是的,如果线程1首先获得互斥锁,则打印的值将为1。这种明确保证的原因是互斥低级别代码和该代码的硬件实现的结合。虽然没有说明,但我假设两段代码属于两个不同的函数(为了简单起见)。请注意,在这种情况下,无论互斥量如何,都不会进行编译器优化-有两个独立的函数,编译器优化是函数的局部优化

在互斥体级别上,互斥体的任何实现都将包括一条直接或间接指令,用于在获取互斥体之前和之后放置内存围栏。这些说明将指示hardwre刷新其所有缓存,因此不会使用缓存值

在哪些情况下,编译器可以根据自己的意愿对指令重新排序

如果编译器能够证明重新排序没有在同一线程中可以观察到的副作用

在某些情况下,此代码是否可以打印1而不是0

没有

当然不是因为编译器对指令进行了重新排序,因为
x
都是在同一线程中读取和写入的,更改顺序以便打印1显然会产生明显的副作用

也不是因为另一个线程写入
x
,因为它是一个自动变量,并且您在任何时候都不获取它的地址,因此很容易证明它不能与其他线程共享

在哪些情况下,编译器可以根据自己的意愿对指令重新排序

如果编译器能够证明重新排序没有在同一线程中可以观察到的副作用

在某些情况下,此代码是否可以打印1而不是0

没有

当然不是因为编译器对指令进行了重新排序,因为
x
都是在同一线程中读取和写入的,更改顺序以便打印1显然会产生明显的副作用


也不是因为另一个线程写入
x
,因为它是一个自动变量,并且您在任何时候都不获取它的地址,因此很容易证明它不能与其他线程共享。

那么其他同步原语(如关键部分)呢?请养成解释自己的习惯。否则,downvote对任何人都没有帮助。虽然结果是真的,但如果没有任何锁,情况显然也是如此。没有死锁的单线程行为不能通过任何优化进行更改(少数例外情况除外),因此,如果我将本例中的
互斥对象更改为关键部分,则可以对其重新排序?@frozenhart,否。编写的代码不会重新排序,既然您有一个
操作符,那么其他的同步原语(如critical Section)呢?请养成解释自己的习惯。否则,downvote对任何人都没有帮助。虽然结果是真的,但如果没有任何锁,情况显然也是如此。没有死锁的单线程行为不能通过任何优化来改变(除了少数例外),因此,如果我将本例中的
互斥对象更改为关键部分,它可以重新排序?@Frozenhart,否。编写的代码不会重新排序,因为您有一个
操作符。这个问题有点让人困惑,您将其标记为多线程,但您的示例涉及自动变量的
cout
输出,这意味着问题实际上是关于单线程的情况。如果这确实是单线程的情况,则此问题涵盖了关键细节。您的问题仍然完全不清楚,现在您添加了第二个,不相关的问题,答案完全不同,解释完全不同。实际上,这两个代码示例之间没有任何关系,而“互斥体”这个词在这里是一个大麻烦。这个问题有点混淆,您将其标记为多线程,但您的示例涉及自动变量的输出
int some_global_variable = 0;

// Thread 1
mutex.lock();
some_global_variable = 1;
mutex.unlock();

// Thread 2
mutex.lock();
std::cout << some_global_variable << std::endl;
mutex.unlock();