[program] Lock Free Update Data Struct
Abstract
- Instead of updating date in-place, create new one then update it’s reference, aka pointer
- It can only archive Eventually Consistent without lock
- The memory barrier of most high-level languages does not ensure that one thread will always be able to read the latest value that modified by other thread
- In a multithreading environment, if you need to ensure that the latest value is accessed every time for variables with simultaneous read and write operations, you must use other synchronization mechanisms to ensure that the CPU row cache is invalidated and synchronized, such as atomic or lock
Introduction
Rule:
- update pointer, rather than update pointer’s data
- free old object
- advance program language do this by GC, low program language must done by itself
- The thread that hold the old refrence will always use the old one, until it read new one
var rcuCfg *RcuCfg
type RcuCfg struct {
cfg *Cfg
lock sync.Mutex //
}
func newCfgFromOld(old *Cfg) {
cfg := &Cfg{}
copy(cfg, old)
return cfg
}
func updateCfg(cfg *Cfg) *Cfg {
// doSomething
return cfg
}
func rcuRead() *Cfg {
return rcuCfg.cfg
}
func rcuUpdate() {
rcuCfg.lock.Lock()
defer rcuCfg.lock.Unlock()
cfg := newCfgFromOld(rcuCfg.cfg)
rcuCfg.cfg = updateCfg(cfg)
}
Reference
- https://www.kernel.org/doc/html/latest/RCU/whatisRCU.html
- https://doc.rust-lang.org/std/sync/atomic/struct.AtomicPtr.html
- https://pkg.go.dev/sync/atomic#Pointer
- https://en.wikipedia.org/wiki/Memory_ordering
- https://en.wikipedia.org/wiki/Memory_barrier
- https://go.dev/ref/mem
- https://en.wikipedia.org/wiki/MESI_protocol
- godbolt - online compiler explorer
- https://en.cppreference.com/w/cpp/atomic/memory_order
- https://en.cppreference.com/w/cpp/atomic/memory_order