天天看點

【高并發】為何在32位多核CPU上執行long型變量的寫操作會出現詭異的Bug問題?看完這篇我懂了!

大家好,我是冰河~~

寫在前面

大冰:小菜童鞋,前幾天講的知識點複習了嗎?

小菜:複習了,大冰哥,我回去關注了你的公衆号,收藏和轉發了你的文章,看了好幾遍呢!!

大冰:好的,一定要好好複習啊,今天,我們來分析一個詭異的問題:為何在32位多核CPU上執行long型變量的寫操作會出現詭異的Bug問題呢? 今天的内容很重要,它能夠幫助你更加深刻的了解線程的原子性問題,一定要好好聽!

詭異的問題

我們在32位多核CPU的計算機上以多線程的方式讀寫long類型的共享變量時,線程已經将變量成功寫入了記憶體,但是重新讀取出來的資料和之前寫入的資料不一緻,這到底是為什麼呢?

原因分析

其實,造成這個問題的根本原因就是線程的原子性問題,而線程的原子性問題最終的“幕後黑手”是線程切換,如果能夠禁用線程切換就能夠解決這個問題了!在作業系統層面來看,作業系統做線程切換需要依賴CPU的中斷機制,是以說,禁止CPU發生中斷就能夠禁止線程切換。

這種方案在單核CPU上是可行的,但是并不适合多核CPU。

其實,就分析為何在32位多核CPU上執行long型變量的寫操作會出現詭異的Bug問題,我們需要從資料類型占用的存儲空間來分析。long型變量是64位的,在32位CPU上執行寫操作會被拆分成兩次寫操作(分别是寫高32位和寫低32位)。我們可以用下圖來表示。

【高并發】為何在32位多核CPU上執行long型變量的寫操作會出現詭異的Bug問題?看完這篇我懂了!

32位單核CPU

在32位單核CPU場景下,同一時刻隻有一個線程執行,禁止CPU中斷,也就是說,在單核CPU上,作業系統不會重新排程線程,實際上,也就是禁止了線程切換。如果一個線程擷取到CPU資源,就可以一直執行下去,直到線程結束為止。在這個線程中,對于long型變量的兩次寫操作,要麼都被執行,要麼都沒有被執行,兩次寫操作具有原子性,不會出現寫入的資料和讀取的資料不一緻的情況。

我們可以簡單的使用下圖來表示32位單核CPU寫long型資料這個過程。

【高并發】為何在32位多核CPU上執行long型變量的寫操作會出現詭異的Bug問題?看完這篇我懂了!

由上圖我們可以看出,在32位單核CPU中,禁止了線程切換之後,所有的線程都是串行執行的,對于long型變量的兩次寫操作,要麼都被執行,要麼都沒有被執行,兩次寫操作具有原子性,不會出現寫入的資料和讀取的資料不一緻的情況。

32位多核CPU

在32位多核CPU場景下,同一時刻,可能有兩個甚至更多的線程在同時執行。假設有兩個線程分别是線程A和線程B,線程A執行在CPU-01上,線程B執行在CPU-02上,此時,禁用CPU中斷,隻能保證在每個CPU上執行的線程是連續的,并不能保證同一時刻隻有一個線程執行,如果線程A和線程B同時寫long型變量的高32位的話,那麼,就有可能出現詭異的Bug問題,也就是說,明明已經将變量成功寫入記憶體了,但是重新讀取出來的資料卻不是自己寫入的!!

我們可以簡單的使用下圖來表示32位多核CPU并發寫long型資料這個過程。

【高并發】為何在32位多核CPU上執行long型變量的寫操作會出現詭異的Bug問題?看完這篇我懂了!

由上圖我們可以看出,在32位多核CPU中,如果有多個線程同時對long類型的資料進行寫操作,即使中斷CPU操作,也隻能保證在每個CPU上執行的線程是連續的,并不能保證同一時刻隻有一個線程執行。如果多個線程同時寫long型變量的高32位的話,那麼,就有可能出現詭異的Bug問題。

總結

long型變量是64位的,在32位CPU上執行寫操作,會被拆分成寫高32位和寫低32位兩部分,如果此時有多個線程同時寫long型變量的高32位的話,就有可能出現詭異的Bug問題。

注意:不隻是long型變量,在32位多核CPU上并發寫64位資料類型的資料,都會出現類似的詭異問題!!!

如果覺得文章對你有點幫助,請微信搜尋并關注「 冰河技術 」微信公衆号,跟冰河學習高并發程式設計技術。

寫在最後

大冰:這就是今天的主要内容了,今天的内容非常重要,它能夠幫助你更加深刻的了解并發程式設計的原子性問題,小菜童鞋,回去後一定要好好複習下。

小菜:好的,大冰哥,回去我一定好好複習。

最後,附上并發程式設計需要掌握的核心技能知識圖,祝大家在學習并發程式設計時,少走彎路。

【高并發】為何在32位多核CPU上執行long型變量的寫操作會出現詭異的Bug問題?看完這篇我懂了!

繼續閱讀