github.com/haraldrudell/parl@v0.4.176/pruntime/cacher.go (about) 1 /* 2 © 2021–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package pruntime 7 8 import ( 9 "sync" 10 "sync/atomic" 11 ) 12 13 // CacheMechanic ensures that an init function is executed exactly once 14 // - sync.Once using a known number of stack frames 15 // - initialization-free 16 type CacheMechanic struct { 17 // first access makes threads wait until data is available 18 // - subsequent accesses is atomic performance 19 initLock sync.Mutex 20 // written inside lock 21 // - isReady read provides happens-before 22 isReady atomic.Bool 23 } 24 25 // EnsureInit ensures data is loaded exactly once 26 // - initFunc loads data 27 // - invocations after first EnsureInit return are atomic performance 28 // - first invocation is locked performance 29 // - subsequent invocations prior to first EnsureInit return are held waiting 30 // - — 31 // - upon return, it is guaranteed that init has completed 32 // - order of thread-returns is not guaranteed 33 func (c *CacheMechanic) EnsureInit(initFunc func()) { 34 35 // ouside lock fast check 36 if c.isReady.Load() { 37 return // already initialized 38 } 39 40 // first thread will win, other threads will wait 41 c.initLock.Lock() 42 defer c.initLock.Unlock() 43 44 // inside lock check 45 if c.isReady.Load() { 46 return // already initialized by other thread 47 } 48 49 // winner thread does init 50 initFunc() 51 52 // flag values available 53 c.isReady.Store(true) 54 }