上卷 程序设计
中卷 标准库
- bufio 1.18
- bytes 1.18
- io 1.18
- container 1.18
- encoding 1.18
- crypto 1.18
- hash 1.18
- index 1.18
- sort 1.18
- context 1.18
- database 1.18
- connection
- query
- queryrow
- exec
- prepare
- transaction
- scan & null
- context
- tcp
- udp
- http
- server
- handler
- client
- h2、tls
- url
- rpc
- exec
- signal
- embed 1.18
- plugin 1.18
- reflect 1.18
- runtime 1.18
- KeepAlived
- ReadMemStats
- SetFinalizer
- Stack
- sync 1.18
- atomic
- mutex
- rwmutex
- waitgroup
- cond
- once
- map
- pool
- copycheck
- nocopy
- unsafe 1.18
- fmt 1.18
- log 1.18
- math 1.18
- time 1.18
- timer
下卷 运行时
源码剖析
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
rwmutex
写锁独占,须等待读锁全部释放。读之间其实不存在锁。
源码剖析
同样是基于运行时信号量实现。
另有 RLocker
方法返回 读锁 的 Locker
接口,解决方法名不同的问题。
// sync/rwmutex.go type RWMutex struct { w Mutex // 写锁,阻止写并发。 writerSem uint32 // 写信号量 readerSem uint32 // 读信号量 readerCount int32 // 读者总数,含新人。 readerWait int32 // 写手需等待的已锁读者数。 }
加锁
读锁仅增加 读者计数器 ( readerCount+1
)即可,无实质性锁定。
计数可能是负数,因为写手会减去常量值( -Max
),使其变成负数。
目的是阻止新读者取锁进入临界区。只能休眠,等写手解锁时唤醒。
func (rw *RWMutex) RLock() { // 正常读锁,计数 +1,结果大于零。 // 负数只能表示写手 -Max 了。 // 累加计数,休眠,等待写手唤醒。 if atomic.AddInt32(&rw.readerCount, 1) < 0 { runtime_SemacquireMutex(&rw.readerSem, false, 0) } }
写手 ,占住写锁( w
),阻止其他写手进入。
将读者计数减去常量值( -Max
),阻止新读者取锁进入临界区。
保存当前已锁读者数( raderWait
)。休眠,等最后的读者解锁时唤醒。
const rwmutexMaxReaders = 1 << 30 func (rw *RWMutex) Lock() { // 先占住写锁。 rw.w.Lock() // 将读者计数变成负数,阻止新读者进入临界区。 r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders // 保存要等待的已锁读者数,休眠。 if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 { runtime_SemacquireMutex(&rw.writerSem, false, 0) } }
解锁
读者解锁时,递减读者计数器。
如结果为负数,表示有写手在等待。递减等待计数。最后一位读者解锁,唤醒写手。
func (rw *RWMutex) RUnlock() { // 如果读计数器是负数,那么是有写手在等待。 if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 { rw.rUnlockSlow(r) } } func (rw *RWMutex) rUnlockSlow(r int32) { // 不成对调用,解锁次数过多。 if r+1 == 0 || r+1 == -rwmutexMaxReaders { race.Enable() throw("sync: RUnlock of unlocked RWMutex") } // 等待数 -1。最后一位,有责任唤醒写手。 if atomic.AddInt32(&rw.readerWait, -1) == 0 { runtime_Semrelease(&rw.writerSem, false, 1) } }
写手解锁时,将读者计数加上常量值( +Max
),其结果就是休眠读者数量。
唤醒所有休眠读者,释放写锁。
func (rw *RWMutex) Unlock() { r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders) // 不成对调用,解锁次数过多。 if r >= rwmutexMaxReaders { race.Enable() throw("sync: Unlock of unlocked RWMutex") } // 根据实际读者数量,一一唤醒。 for i := 0; i < int(r); i++ { runtime_Semrelease(&rw.readerSem, false, 0) } rw.w.Unlock() }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论