• +1day
    2020-10-23
    老师您好,在获取等待者数量的代码中 如果要加上锁持有者的数量的话,为什么不是 v = v >> mutexWaiterShift + (v & mutexLocked) 而是 v = v >> mutexWaiterShift //得到等待者的数值 v = v + (v & mutexLocked) //再加上锁持有者的数量,0或者1 这样呢?第一步修改了 v 的值,v 的第一位已经不再是记录该锁是否被持有了,那 v&mutexLocked 是不是不对呢?

    作者回复: 你说的对

    共 7 条评论
    22
  • Panmax
    2020-10-24
    如果底层 Mutex 的 state 在某个版本中含义变了,上边写的 TryLock 和监控锁的一些方法就会失效,所以这样做是不是比较危险。

    作者回复: 是的.这只是hack方式,和go的版本有关系。

    共 4 条评论
    7
  • 不二
    2020-10-20
    请教一个基础问题,为啥 (*int32)(unsafe.Pointer(&m.Mutex)) 可以获取sync.Mutex中state的值,Mutex结构中不是还有sema吗?

    作者回复: 只取第一个用

    共 7 条评论
    5
  • Gojustforfun
    2020-10-20
    1)『获取等待者的数量等指标』小节,『第 15 行我们左移三位(这里的常量 mutexWaiterShift 的值为 3)』应该是右移三位。 2)在now~now+timout内,间隔重试调用TryLock

    作者回复: 多谢

    
    2
  • 天空之城
    2023-05-12 来自北京
    关于 RWLock 的扩展,我这边给出一段代码(评论不好贴代码,贴个 share link) https://go.dev/play/p/X4YNwqZR4ta ```go package sync import ( "sync" "sync/atomic" "unsafe" ) type RWMutex struct { rw sync.RWMutex } const ( mutexLocked = 1 << iota mutexWake mutexStarving mutexWaiterShift = iota ) const ( rwmutexMaxReaders = 1 << 30 ) func (e *RWMutex) TryLock() bool { if e.GetReader() < 0 { return false } e.rw.Lock() return true } // readerCount > 0 => Reader Hold without Writer, <0 => Reader Hold and Writer waiting, ==0 => no reader // state.mutexLocked == 1 => Writer Hold (in the meanwhile, readerWaiter==0, all reader(readerCount) are waiting) func (e *RWMutex) IsLocked() bool { return e.IsWriterLocked() || e.IsReaderLocked() } func (e *RWMutex) IsWriterLocked() bool { state := atomic.LoadInt32((*int32)(unsafe.Pointer(&e.rw))) return state&mutexLocked == mutexLocked } func (e *RWMutex) IsReaderLocked() bool { return atomic.LoadInt32(e.readerCountPtr()) != 0 } func (e *RWMutex) HasWriter() bool { return atomic.LoadInt32(e.readerCountPtr()) < 0 } func (e *RWMutex) GetWriter() int32 { state := atomic.LoadInt32((*int32)(unsafe.Pointer(&e.rw))) return int32((state >> mutexWaiterShift) + (state & mutexLocked)) } func (e *RWMutex) HasReader() bool { return atomic.LoadInt32(e.readerCountPtr()) != 0 } func (e *RWMutex) GetReader() int32 { r := atomic.LoadInt32(e.readerCountPtr()) if r < 0 { r += rwmutexMaxReaders } return r } func (e *RWMutex) readerCountPtr() *int32 { return (*int32)(unsafe.Pointer(uintptr(unsafe.Pointer(&e.rw)) + unsafe.Sizeof(sync.Mutex{}) + unsafe.Sizeof(uint32(0))*2)) } func (e *RWMutex) readerWaitPtr() *int32 { return (*int32)(unsafe.Pointer(uintptr(unsafe.Pointer(&e.rw)) + unsafe.Sizeof(sync.Mutex{}) + unsafe.Sizeof(uint32(0))*2 + unsafe.Sizeof((int32(0))))) } ```
    展开

    作者回复: 👍🏻

    
    1
  • 斯蒂芬.赵
    2021-05-07
    fast path执行失败,直接返回false不就行了,为啥还要往下执行?正常不是多个携程并发只有一个执行成功,其他都是失败么?

    作者回复: 尝试和唤醒的goroutine抢一抢。 当然为了简单不易出错,return false更好,容易理解,不易出错

    共 3 条评论
    1
  • 路过
    2023-04-17 来自广东
    想问一下,为什么最后实现线程安全的队列里面的 Dequeue() 方法释放锁不用defer,这样不用写两次unlock

    作者回复: 尽早释放锁

    
    
  • 鲁迅原名周树人
    2021-05-03
    老师您好, // 如果能成功抢到锁 if atomic.CompareAndSwapInt32((*int32)(unsafe.Pointer(&m.Mutex)), 0, mutexLocked) { return true } 在以上代码中,(*int32)(unsafe.Pointer(&m.Mutex))是取的Mutex中state的首地址对嘛?

    作者回复: 对

    共 2 条评论
    
  • 黄毅
    2020-11-16
    func (m *Mutex) TryLock() bool { // 如果能成功抢到锁 if atomic.CompareAndSwapInt32((*int32)(unsafe.Pointer(&m.Mutex)), 0, mutexLocked) { return true } // 如果处于唤醒、加锁或者饥饿状态,这次请求就不参与竞争了,返回false old := atomic.LoadInt32((*int32)(unsafe.Pointer(&m.Mutex))) fmt.Println("===old===:", old) if old&(mutexLocked|mutexStarving|mutexWoken) != 0 { return false } // 尝试在竞争的状态下请求锁 new := old | mutexLocked fmt.Println("===new===:", new) //请问在什么情况下会执行到这里 return atomic.CompareAndSwapInt32((*int32)(unsafe.Pointer(&m.Mutex)), old, new) } func main() { var mu Mutex go func() { // 启动一个goroutine持有一段时间的锁 mu.Lock() time.Sleep(time.Duration(rand.Intn(2)) * time.Second) mu.Unlock() }() time.Sleep(time.Second) n := int(10) var wg sync.WaitGroup wg.Add(n) for i := 0; i < n; i++ { go func() { ok := mu.TryLock() // 尝试获取到锁 defer wg.Done() if ok { // 获取成功 fmt.Println("got the lock") // do something mu.Unlock() return } }() } // 没有获取到 wg.Wait() } 老师,你好。在main中尝试编写一段逻辑测试TryLock方法,请问在什么情况下会执行fmt.Println("===new===:", new) 请老师答疑解惑,谢谢。
    展开

    作者回复: 在大并发竞争锁,在释放锁的时候可能会出现。很极端的情况,可能难以模拟,但是通过分析mutex的lock/unlock代码应该能分析出来。 另外如果trylick简单实现,可以只保留第一段,其它情况返回false即可

    
    
  • 樊少
    2020-11-05
    在安全Queue的实现中,锁的释放为什么不用defer?

    作者回复: 可以用

    
    