~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/Documentation/translations/zh_TW/process/volatile-considered-harmful.rst

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 .. SPDX-License-Identifier: GPL-2.0
  2 
  3 .. _tw_volatile_considered_harmful:
  4 
  5 .. include:: ../disclaimer-zh_TW.rst
  6 
  7 :Original: :ref:`Documentation/process/volatile-considered-harmful.rst
  8            <volatile_considered_harmful>`
  9 
 10 如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
 11 交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻
 12 譯存在問題,請聯繫中文版維護者::
 13 
 14         英文版維護者: Jonathan Corbet <corbet@lwn.net>
 15         中文版維護者: 伍鵬  Bryan Wu <bryan.wu@analog.com>
 16         中文版翻譯者: 伍鵬  Bryan Wu <bryan.wu@analog.com>
 17         中文版校譯者: 張漢輝  Eugene Teo <eugeneteo@kernel.sg>
 18                        楊瑞  Dave Young <hidave.darkstar@gmail.com>
 19                        時奎亮 Alex Shi <alex.shi@linux.alibaba.com>
 20                        胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
 21 
 22 爲什麼不應該使用“volatile”類型
 23 ==============================
 24 
 25 C程序員通常認爲volatile表示某個變量可以在當前執行的線程之外被改變;因此,在內核
 26 中用到共享數據結構時,常常會有C程序員喜歡使用volatile這類變量。換句話說,他們經
 27 常會把volatile類型看成某種簡易的原子變量,當然它們不是。在內核中使用volatile幾
 28 乎總是錯誤的;本文檔將解釋爲什麼這樣。
 29 
 30 理解volatile的關鍵是知道它的目的是用來消除優化,實際上很少有人真正需要這樣的應
 31 用。在內核中,程序員必須防止意外的併發訪問破壞共享的數據結構,這其實是一個完全
 32 不同的任務。用來防止意外併發訪問的保護措施,可以更加高效的避免大多數優化相關的
 33 問題。
 34 
 35 像volatile一樣,內核提供了很多原語來保證併發訪問時的數據安全(自旋鎖, 互斥量,內
 36 存屏障等等),同樣可以防止意外的優化。如果可以正確使用這些內核原語,那麼就沒有
 37 必要再使用volatile。如果仍然必須使用volatile,那麼幾乎可以肯定在代碼的某處有一
 38 個bug。在正確設計的內核代碼中,volatile能帶來的僅僅是使事情變慢。
 39 
 40 思考一下這段典型的內核代碼::
 41 
 42     spin_lock(&the_lock);
 43     do_something_on(&shared_data);
 44     do_something_else_with(&shared_data);
 45     spin_unlock(&the_lock);
 46 
 47 如果所有的代碼都遵循加鎖規則,當持有the_lock的時候,不可能意外的改變shared_data的
 48 值。任何可能訪問該數據的其他代碼都會在這個鎖上等待。自旋鎖原語跟內存屏障一樣—— 它
 49 們顯式的用來書寫成這樣 —— 意味着數據訪問不會跨越它們而被優化。所以本來編譯器認爲
 50 它知道在shared_data裏面將有什麼,但是因爲spin_lock()調用跟內存屏障一樣,會強制編
 51 譯器忘記它所知道的一切。那麼在訪問這些數據時不會有優化的問題。
 52 
 53 如果shared_data被聲名爲volatile,鎖操作將仍然是必須的。就算我們知道沒有其他人正在
 54 使用它,編譯器也將被阻止優化對臨界區內shared_data的訪問。在鎖有效的同時,
 55 shared_data不是volatile的。在處理共享數據的時候,適當的鎖操作可以不再需要
 56 volatile —— 並且是有潛在危害的。
 57 
 58 volatile的存儲類型最初是爲那些內存映射的I/O寄存器而定義。在內核裏,寄存器訪問也應
 59 該被鎖保護,但是人們也不希望編譯器“優化”臨界區內的寄存器訪問。內核裏I/O的內存訪問
 60 是通過訪問函數完成的;不贊成通過指針對I/O內存的直接訪問,並且不是在所有體系架構上
 61 都能工作。那些訪問函數正是爲了防止意外優化而寫的,因此,再說一次,volatile類型不
 62 是必需的。
 63 
 64 另一種引起用戶可能使用volatile的情況是當處理器正忙着等待一個變量的值。正確執行一
 65 個忙等待的方法是::
 66 
 67     while (my_variable != what_i_want)
 68         cpu_relax();
 69 
 70 cpu_relax()調用會降低CPU的能量消耗或者讓位於超線程雙處理器;它也作爲內存屏障一樣出
 71 現,所以,再一次,volatile不是必需的。當然,忙等待一開始就是一種反常規的做法。
 72 
 73 在內核中,一些稀少的情況下volatile仍然是有意義的:
 74 
 75   - 在一些體系架構的系統上,允許直接的I/0內存訪問,那麼前面提到的訪問函數可以使用
 76     volatile。基本上,每一個訪問函數調用它自己都是一個小的臨界區域並且保證了按照
 77     程序員期望的那樣發生訪問操作。
 78 
 79   - 某些會改變內存的內聯彙編代碼雖然沒有什麼其他明顯的附作用,但是有被GCC刪除的可
 80     能性。在彙編聲明中加上volatile關鍵字可以防止這種刪除操作。
 81 
 82   - Jiffies變量是一種特殊情況,雖然每次引用它的時候都可以有不同的值,但讀jiffies
 83     變量時不需要任何特殊的加鎖保護。所以jiffies變量可以使用volatile,但是不贊成
 84     其他跟jiffies相同類型變量使用volatile。Jiffies被認爲是一種“愚蠢的遺留物"
 85     (Linus的話)因爲解決這個問題比保持現狀要麻煩的多。
 86 
 87   - 由於某些I/0設備可能會修改連續一致的內存,所以有時,指向連續一致內存的數據結構
 88     的指針需要正確的使用volatile。網絡適配器使用的環狀緩存區正是這類情形的一個例
 89     子,其中適配器用改變指針來表示哪些描述符已經處理過了。
 90 
 91 對於大多代碼,上述幾種可以使用volatile的情況都不適用。所以,使用volatile是一種
 92 bug並且需要對這樣的代碼額外仔細檢查。那些試圖使用volatile的開發人員需要退一步想想
 93 他們真正想實現的是什麼。
 94 
 95 非常歡迎刪除volatile變量的補丁 - 只要證明這些補丁完整的考慮了併發問題。
 96 
 97 註釋
 98 ----
 99 
100 [1] https://lwn.net/Articles/233481/
101 [2] https://lwn.net/Articles/233482/
102 
103 致謝
104 ----
105 
106 最初由Randy Dunlap推動並作初步研究
107 由Jonathan Corbet撰寫
108 參考Satyam Sharma,Johannes Stezenbach,Jesper Juhl,Heikki Orsila,
109 H. Peter Anvin,Philipp Hahn和Stefan Richter的意見改善了本檔。
110 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php