1. 程式人生 > 其它 >多執行緒環境下,程式執行真是危機四伏

多執行緒環境下,程式執行真是危機四伏

姿勢在不斷的更新迭代, 太捲了。

你管這也叫執行緒安全?

最近大意了,竟然想將《面試官:實現一個帶值變更通知能力的Dictionary》一文中的臨界鎖只應用到寫操作。

內心旁白:
讀操作又不會修改資料,無論是新值還是舊值,反正能讀到。

不過我又快速清醒了,臨界鎖還真就得這麼加。
臨界鎖的目的是保證這一段程式碼邏輯不會被打斷。

假如只應用寫鎖:

某執行緒執行到寫鎖前(剛觸發了一次變通通知),這時cpu時間片輪轉或搶佔, 切換到另外的執行緒又把這段程式碼執行了一次(因為字典key-value還沒被前執行緒覆寫),這樣一次value變更實際執行了兩次變通操作,這就悲劇了。


結合之間《你管這叫執行緒安全?》一文中多執行緒對於i++

i--帶來的執行緒不安全的理解。

你品你細品, 本次執行緒安全是在巨集觀程式碼行執行層面,
上次的i++ 是在微觀暫存器層面, 歸根到底還是要讓多執行緒在多核環境下:程式碼邏輯不能被打斷(程式碼執行節奏可能被打斷)

多執行緒環境下,程式執行真是危機四伏。

微軟官方怎麼說?

還沒完, 我還從微軟官方原子操作找到一段話:

Reads and writes of the following data types are atomic: bool, char, byte, sbyte, short, ushort, uint, int, float, and reference types. In addition, reads and writes of enum types with an underlying type in the previous list are also atomic. Reads and writes of other types, including long, ulong, double, and decimal, as well as user-defined types, are not guaranteed to be atomic. Aside from the library functions designed for that purpose, there is no guarantee of atomic read-modify-write, such as in the case of increment or decrement.

直譯起來:
① bool char byte sbyte uint int float 和引用型別上的讀寫是原子操作;

② 由以上型別定義的列舉型別操作也是原子型別;

③ long ulong double decimal和使用者定義型別上的讀寫不保證是原子操作;

④ 除了庫檔案本身設計了執行緒安全,一般況下下都不保證讀寫是原子操作, 這也包括i++i--

這段文字是不是重新整理了某些童靴的認知(包括在下):

  1. 以後使用long num=8888;時要留個心眼,你也許會讀到long型別的部分位元組。

  2. 直譯第①點說引用型別的讀寫是原子操作,第③點說使用者型別不保證原子操作,但是大部分的使用者型別是引用型別,這不互相矛盾了嗎?

我向微軟官方提出了我的這個疑問,有興趣可以關注這個github issue

說說我的看法:

直譯第①點中各種型別的讀寫操作是原子操作: 應該想表示式是純粹的賦值、引用操作, 比如

int a =1;   				  //  賦值:  執行緒安全
Student s = new Student {}; 	          // 引用賦值: 執行緒安全
Student  s2= s;                           // 引用賦值: 執行緒安全

針對引用型別Dictionary的其他操作自然不是執行緒安全的。

依據這個思路, 第①③點就不矛盾了。


That's All, 本文依舊是#執行緒安全#、#鎖# 這兩個老生常談的概念的延續, 我的知識體系也是在不斷迭代更新,不斷精煉。

我也沒想到越挖越深,真的是太捲了,如有不同的看法,請留言交流。


本文來自部落格園,作者:{有態度的馬甲},轉載請註明原文連結:https://www.cnblogs.com/JulianHuang/p/15267756.html

歡迎關注我的原創高價值公眾號