高併發之——你知道爲何在32位多核CPU上執行long型變量的寫操作會出現詭異的Bug問題嗎?

詭異的問題:

我們在32位多核CPU的計算機上以多線程的方式讀寫long類型的共享變量時,明明已經將變量成功寫入內存了,但是重新讀取出來的數據卻不是自己寫入的,這是爲什麼呢?

原因分析:

其實,造成這個問題的根本原因就是線程的原子性問題,而線程的原子性問題的源頭是線程切換,如果能夠禁用線程切換就能夠解決這個問題了!在操作系統層面來看,操作系統做線程切換依賴CPU中斷機制,所以說,禁止CPU發生中斷就能夠禁止線程切換。

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

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

在這裏插入圖片描述

32位單核CPU

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

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

在這裏插入圖片描述

由上圖我們可以看出,在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類型的數據進行寫操作,即使中斷CPU操作,也只能保證在每個CPU上執行的線程是連續的,並不能保證同一時刻只有一個線程執行。如果多個線程同時寫long型變量的高32位的話,那麼,就有可能出現詭異的Bug問題。

總結

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

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章