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 }