github.com/chanxuehong/wechat@v0.0.0-20230222024006-36f0325263cd/mp/core/started_checker.go (about)

     1  package core
     2  
     3  import (
     4  	"sync/atomic"
     5  )
     6  
     7  const (
     8  	startedCheckerInitialValue = uintptr(0)
     9  	startedCheckerStartedValue = ^uintptr(0)
    10  )
    11  
    12  // 正常情况下实例的配置方法和服务方法是不能并行执行的(这两种方法竞争同一份配置数据), 一般我们有两种方案:
    13  // 1. 用互斥锁
    14  // 2. 明确文档告知该实例不是并行安全的
    15  // 对于第2种场景, 很多程序员有可能不小心并行执行了该实例的配置方法和服务方法, 那有没有好的解决方案呢?
    16  // 其实在大部分场景下, 实例可以先配置, 投入服务后就没有必要修改其配置了(如果有必要修改的只能用互斥锁了),
    17  // startedChecker 就是为这种场景设计的, 能在很大程度上保证数据安全(不是绝对, 极小的概率下会出现数据竞争).
    18  type startedChecker uintptr
    19  
    20  func (p *startedChecker) start() {
    21  	if uintptr(*p) == startedCheckerInitialValue {
    22  		atomic.CompareAndSwapUintptr((*uintptr)(p), startedCheckerInitialValue, startedCheckerStartedValue)
    23  	}
    24  }
    25  
    26  func (v startedChecker) check() {
    27  	if uintptr(v) != startedCheckerInitialValue {
    28  		panic("the service has been started.")
    29  	}
    30  }