簡體   English   中英

x86 內存排序測試顯示在英特爾手冊中說不應該重新排序的地方?

[英]x86 memory ordering test shows reordering where Intel's manual says there shouldn't be?

根據英特爾的手冊。 根據 8.2.3.2 既不加載也不使用相似操作重新排序加載和存儲也不使用相似操作重新排序

在文檔https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-3a-part-1-manual.html輸入圖片說明在這里

但是我創建了一個簡單的案例,我發現 r1=1 和 r2=2 發生了。

#include <thread>
#include <iostream>

using namespace std;

volatile int x;
int b[500];
volatile int y;
volatile int start;

int s1;
int s2;
int s3;
int s0;
int foo()
{
    while(start==0);
    x=1;
    asm volatile("" ::: "memory");
    y=1;
    return 0;
}

int fool2()
{
    int a,b;
    while(start==0);
    a=x;
    asm volatile("" ::: "memory");
    b=y;

   if(a==0 && b==1)
         s0++;
   if(a==0 && b==0)
         s1++;
   if(a==1 && b==0)
         s2++;
   if(a==1 && b==1)
        s3++;
   return 0;
}

int main()
{
  int i=0;
  while(1)
  {
     x=y=0;
     thread t1(foo);
     thread t2(fool2);
     start = 1;
     t1.join();
     t2.join();
     i++;
     if((i&0xFFFF)==0)
     {
           cout<<s0<<" "<<s1<<" "<<s2<<" "<<s3<<endl;
     }
  }
}

g++ -O2 -pthread e.cpp

gcc 版本 7.5.0

輸出:

69 86538 1 19246512

四種情況(r1 和 r2 與 0、1 組合)都是可能的。

仔細看看intel手冊的第8.2.3.2節是什么。 在您的示例中,您正在有效地執行以下操作:

處理器 1 處理器 2
移動 [_x], 1 移動 r2, _x
移動 [_y], 1 移動 r1, _y

而不是英特爾手冊所說的:

處理器 1 處理器 2
移動 [_x], 1 移動 r1, _y
移動 [_y], 1 移動 r2, _x

在您的示例中,處理器 2 可能會在處理器 1 設置 _x 之前加載 _x,然后在處理器 1 存儲它之后加載 _y,從而允許 (r1=1, r2=0):

操作說明 處理器
移動 r2, _x 2
移動 [_x], 1 1
移動 [_y], 1 1
移動 r1, _y 2

在英特爾示例中,處理器 2 只能在加載 _y 后加載 _x,而處理器 1 僅在設置 _x 后才設置 _y,因此 (r1=1, r2=0) 是不可能的。

下面是一些演示英特爾行為的代碼:

#include <thread>
#include <iostream>
#include <stdlib.h>

using namespace std;

volatile int x;
volatile int y;
volatile int start;

constexpr bool flipOrdering = true; //Set this to true to see Intel example, false to see your example
constexpr int jitter = 10000;       //Range of random delay inserted between load/stores to make differences more obvious

int s1;
int s2;
int s3;
int s0;
int foo() {

    while(start==0);

    for(volatile int i = rand()%jitter; i; --i);
    x = 1;
    
    for(volatile int i = rand()%jitter; i; --i);
    asm volatile("" ::: "memory");

    for(volatile int i = rand()%jitter; i; --i);
    y = 1;

    return 0;
}

int fool2() {
    int a, b;
    while(start==0);

    for(volatile int i = rand()%jitter; i; --i);
    if constexpr(flipOrdering) b = y;
    else a = x;

    for(volatile int i = rand()%jitter; i; --i);
    asm volatile("" ::: "memory");

    for(volatile int i = rand()%jitter; i; --i);
    if constexpr(flipOrdering) a = x;
    else b = y;

   if(a==0 && b==1)
         s0++;
   if(a==0 && b==0)
         s1++;
   if(a==1 && b==0)
         s2++;
   if(a==1 && b==1)
        s3++;

    return 0;
}

int main() {
    int i=0;
    while(i< 1000) {
        x=y=0;
        thread t1(foo);
        thread t2(fool2);
        start = 1;
        t1.join();
        t2.join();
        i++;

        if((i%100)==0) {
            cout<<s0<<" "<<s1<<" "<<s2<<" "<<s3<<endl;
        }
    }

    return 0;
}

這是在編譯器資源管理器中運行的相同代碼的鏈接

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM