簡體   English   中英

全局變量在 C 中的緊密循環中讀取

[英]Global variable reads inside tight loops in C

假設我在 C 中有一個緊密循環,在其中我使用全局變量的值來執行一些算術運算,例如

double c;
// ... initialize c somehow ...

double f(double*a, int n) {
  double sum = 0.0;
  int i;
  for (i = 0; i < n; i++) {
    sum += a[i]*c;
  }
  return sum;
}

使用c全局變量。 c是否在每次循環迭代中“從全局范圍重新讀取”? 畢竟,它可能已被執行其他 function 的其他線程更改,對吧? 因此,通過在循環之前獲取c的本地(函數堆棧)副本並僅使用此副本,代碼會更快嗎?

double f(double*a, int n) {
  double sum = 0.0;
  int i;
  double c_cp = c;
  for (i = 0; i < n; i++) {
    sum += a[i]*c_cp;
  }
  return sum;
}

雖然我沒有具體說明c是如何初始化的,但我們假設它是以某種方式完成的,因此在編譯時該值是未知的。 此外, c在整個運行時實際上是一個常量,即我作為程序員知道它的值不會改變。 我可以讓編譯器了解這些信息嗎,例如在全局 scope 中使用static double c c? 這會改變a[i]*ca[i]*c_cp問題嗎?

我自己的研究

  • 閱讀例如這個的“全局變量”部分,似乎很清楚獲取全局變量的本地副本是通往 go 的途徑。但是,他們想要更新全局變量的值,而我只想讀取它價值。
  • 使用godbolt我沒有注意到cc_cpdouble cstatic double c的任何真正差異。

任何相當聰明的編譯器都會優化您的代碼,因此它會像您的第二個代碼片段一樣運行。 使用static不會有太大變化,但如果您想確保每次迭代都讀取,則使用volatile

關於來自不同線程的更改的要點。 就單線程執行而言,編譯器將保持代碼的完整性。 這意味着它可以重新排序您的代碼,跳過某些內容,添加某些內容——只要最終結果仍然相同。

對於多線程,您的工作是確保事情仍然按特定順序發生,而不僅僅是最終結果是正確的。 確保的方式是memory障礙。 這是一個有趣的話題,但除非您是專家,否則最好避免閱讀。

一旦所有內容都翻譯成機器代碼,您將不會有任何區別。 如果 c 是全局的,則對 c 的任何訪問都將引用 c 的地址,或者最有可能在緊密循環中將 c 保存在寄存器中,或者在最壞的情況下保存在 L1 緩存中。

在 Linux 機器上,您可以輕松生成程序集並檢查生成的代碼。

您還可以運行基准測試。

暫無
暫無

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

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