簡體   English   中英

為什么全局變量會對函數調用中的編譯器優化造成麻煩?

[英]Why do global variables cause trouble for compiler optimizations in function calls?

http://www.hpl.hp.com/techreports/2004/HPL-2004-209.pdf

為了防止編譯器在調用pthread Mutex lock()函數時圍繞內存操作移動它們,它們實際上被視為對不透明函數的調用,編譯器對此不了解任何信息。 編譯器有效地假設pthread互斥lock()可以讀取或寫入任何全局變量。 因此,不能簡單地在調用中移動內存引用。 這種方法還確保傳遞調用(例如,對函數f()調用,然后再調用pthread互斥lock()或多或少地以相同的方式處理,即,在調用f()不會移動內存操作是否立即分析整個用戶程序。

為什么會這樣呢? 為什么引用不能移動的任何反例?

編譯器可以自由移動代碼。 (略有簡化)要求是沒有可見的副作用。

本文介紹了為什么需要在編譯器級別而不是庫級別支持線程。 因此,讓我們考慮一下編譯器正在優化代碼時的含義。 我將從Kerrek SB的優秀示例開始,因為此回復對於評論太長了。

int x = 0;
pthread_mutex_lock(&m);
x = y;

優化器看到的值不會被修改,但會被設置兩次。 copmiler可以訪問該函數內部的代碼,並且看不到任何東西可以修改賦值。 由於沒有可見的副作用,優化器可以消除分配給零的值,而只需將其替換為y的值即可。 優化器將其刪除,將其轉換為:

pthread_mutex_lock(&m);
int x = y;

這可能不會影響任何東西,變量x是局部變量,沒有其他影響。

現在讓我們做一個更具問題的人為例子。

if(globals.hasData) {
  int prelock_value = globals.foo;
  pthread_mutex_lock(&m);
  if(prelock_value != globals.foo) {
    // value changed before we could lock it, do something different
    DoSpecialStuffSinceValueChangedWhileWaiting();
    pthread_mutex_unlock(&m);
    return;
  }
  DoOtherStuff();
  ...

因此,現在我們將從優化器的角度進行研究。 優化器會看到您讀取了一個值,然后執行了一些不會修改該值的操作,然后針對剛存儲的值進行了測試。 由於它看不到可見的副作用,因此可能會像這樣刪除比較:

if(globals.hasData) {
  int prelock_value = globals.foo;
  pthread_mutex_lock(&m);
  if( false /* always false: prelock_value != globals.foo */ ) {
    // value changed before we could lock it, do something different
    DoSpecialStuffSinceValueChangedWhileWaiting();
    pthread_mutex_unlock(&m);
    return;
  }
  DoOtherStuff();
  ...

然后,它看起來再次刪除了無效代碼。 由於if的結果始終為false,因此它會看到對整數的不必要賦值和不必要的條件,並得出以下結論:

if(globals.hasData) {
  pthread_mutex_lock(&m);
  // everything was removed.
  DoOtherStuff();

如果將其與原始函數進行比較,則可以很清楚地看出這根本不是程序員想要的。

這些年來,已經發現了大量潛在的優化方法。 他們中的許多人都假設將代碼從一個地方移到另一個地方的安全性,或者假設值只能由該代碼塊修改。 這些假設在並發編程中可能會嚴重破壞。

優化器需要了解功能的某些位不能移動,並且某些功能會成為無法跨越的障礙,否則會使優化器的假設無效。

暫無
暫無

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

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