golang:atomic.Pointer

发布于:2024-05-04 ⋅ 阅读:(162) ⋅ 点赞:(0)

1.atomic.Pointer 

atomic.Pointer 是 Go 语言标准库 sync/atomic 提供的一种原子指针类型。它用于在并发环境中对指针进行原子操作,以确保线程安全性。

什么是原子操作?golang 的原子操作

在多线程编程中,当多个线程同时访问和修改同一个共享变量时,可能会引发竞态条件(Race Condition)和数据竞争(Data Race)等问题。为了避免这些问题,Go 语言提供了原子操作来确保对共享变量的原子性访问和修改。

type tradeHistory struct {
	latestPopTrade       atomic.Pointer[utils.Trade]
	latestTrade          atomic.Pointer[utils.Trade]
}

2. 原子操作函数

atomic.Pointer 类型实际上是一个指向任意类型的指针,它提供了以下原子操作函数来访问和修改指针的值:

  • func LoadPointer(addr *unsafe.Pointer) (p unsafe.Pointer)

    • LoadPointer 函数用于原子地读取指针的值,并返回读取的值。
    • 参数 addr 是一个指向 unsafe.Pointer 类型的指针,表示要读取的指针的地址。
  • func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer)

    • StorePointer 函数用于原子地存储指针的值。
    • 参数 addr 是一个指向 unsafe.Pointer 类型的指针,表示要存储的指针的地址。
    • 参数 val 是要存储的指针的值。
  • func SwapPointer(addr *unsafe.Pointer, new unsafe.Pointer) (old unsafe.Pointer)

    • SwapPointer 函数用于原子地交换指针的值,并返回原来的值。
    • 参数 addr 是一个指向 unsafe.Pointer 类型的指针,表示要交换值的指针的地址。
    • 参数 new 是要替换的新值。
    • 返回值是原来的指针值。

通过使用这些原子操作函数,可以在多线程环境中对指针进行原子读取、存储和交换操作,从而保证对共享指针的线程安全访问。

3. store和load方法详解

由于这两个方法用得比较多,在 Go 语言中,.Store 和 .Load 是 sync/atomic 包提供的原子操作函数,用于对变量进行原子的存储和加载操作。

Store 函数用于原子存储(写入)变量的值,

 func Store<T>(addr *T, val T)

    (1)Store 函数用于原子地将 val 存储到 addr 所指向的变量中。

           (2) 参数 addr 是一个指向要存储值的变量的指针。

           (3) 参数 val 是要存储的值,类型必须与 addr 指向的变量类型相同。

Load 函数用于原子加载(读取)变量的值。

    func Load<T>(addr *T) T

   (1)Load 函数用于原子地加载 addr 所指向的变量的值。

         (2)参数 addr 是一个指向要加载值的变量的指针。

         (3)返回值是加载的值,类型与 addr 指向的变量类型相同。

func (t *tradeHistory) addTrade(trade *utils.Trade) {
	if t.latestTrade.Load() == nil {
		t.latestTrade.Store(trade)
		return
	}
	if t.latestButOneTrade.Load() == nil {
		t.latestButOneTrade.Store(t.latestTrade.Load())
		t.latestTrade.Store(trade)
		return
	}
	t.latestButOneTrade.Store(t.latestTrade.Load())
	t.latestTrade.Store(trade)
	t.tradeHisBase.addTrade(trade)
	t.maxVolPrc.AddTrade(trade)
	t.sortHisPrc.Add(trade.GetPrc())
	t.sortHisNotional.Add(trade.GetAmt())
	t.prcDiffQueue.Add(trade.GetPrc()/t.latestButOneTrade.Load().GetPrc() - 1)
}