【Go】原子操作atomic.Value的使用


概述
Go的sync/atomic包提供了原子操作,支持的數據類型包括:

int32, int64, uint32, uint64, uintptr, unsafe.Pointer
1
若需要擴大原子操作的適用范圍,可以使用atomic包中的Value。利用它可以實現對任意值進行原子得存儲與加載。

使用注意點
atomic.Value只有兩個指針方法:Store、Load。使用時需要遵循兩個原則:1.不能存儲nil;2.存儲第一個值后,就只能存儲這個類型的值。
看一下atom.Value的實現可以發現一個內部的結構ifaceWords,使用unsafe.Pointer存儲數據類型及內容得指針

type ifaceWords struct {
typ unsafe.Pointer
data unsafe.Pointer
}
1
2
3
4
在使用Store進行存儲時,首先判斷待存儲值是否為nil,若為nil會直接panic。之后會讀取typ,若為nil則會將待存儲值得類型、值的指針分別對typ、data進行賦值;若不為nil,則會判斷待存儲值的類型是否與既有的typ一致,不一致也會引起panic,一致的話則是將新值的指針賦予data。
為了防止在使用是意外出現panic,所以可以考慮在外部先進行合法性校驗。

引用類型帶來的坑點
因為atom.Value內部實際上維護的是存儲值的指針,而這個指針因為不對外暴露,所以認為是並發安全的。然而如果嘗試用它來存儲引用類型,維護的就是這個引用類型的指針,則不能保證實際的數據是並發安全的。舉個例子:
uint32是值類型,切片[]uint32是引用類型,我們使用這樣兩個函數來嘗試修改值。

//值類型
func atomic_value(a uint32) {
var v atomic.Value
v.Store(a)
a = 666
fmt.Println(a)
fmt.Println(v.Load())
}

// 引用類型
func atomic_slice(s []uint32) {
var v atomic.Value
v.Store(s)
s[0] = 666
fmt.Println(s)
fmt.Println(v.Load())
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
然后我們分別調用這兩個函數

func TestAtomValue(t *testing.T) {
atomic_value(1)
atomic_slice([]uint32{1,2,3})
}
1
2
3
4
最后它的輸出是這樣的:

可以看到我們使用Store存入uint32的值a后,我們無論怎么在外部修改a,使用Load都可以獲取到我們Store的值。
然而我們若使用Store存入引用類型的切片,我們在外部修改值,Load出來的值也會收到影響。這是因為對於一個引用類型,我們實際上只是Store了一個指針,只是對一個指針的原子操作,而這個指針實際指向的地址的值,並不在atomic.Value的維護下,所以並不是並發安全的。

總結
1.atomic.Value可以實現對自定義類型的原子操作
2.不能存入nil
3.對於同一個atomic.Value不能存入類型不同的值
4.最好不要使用atomic.Value存儲引用類型的值,可能導致數據不是並發安全的
————————————————
版權聲明:本文為CSDN博主「雨兒醬在鹿上」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/q895431756/article/details/111063656


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM