• DigDeeply
    2020-12-04
    这门课的质量真高啊,看的酣畅淋漓👍

    作者回复: 这是对作者很高的褒奖,谢谢。此留言应该置顶啊

    
    27
  • 那时刻
    2020-10-23
    请问老师一个关于select{}问题, func foo() { fmt.Println("in foo") } func goo() { var i int fmt.Println("in goo", i) } func main() { go goo() go foo() select {} } 这个代码会报all goroutines are asleep - deadlock,是不是select{}这种写法不推荐么?

    作者回复: 现在版本的go运行时过于智能了,会把这个场景“误报”成死锁,其实我们的本意是让程序hang在这里。 可以改成sleep,waitgroup或者从命令行读取数据等的方式阻塞主goroutine

    
    8
  • Varphp
    2021-01-16
    原谅我的小白 请教个问题 RWMutex是读写锁,Mutex就是锁吗?区别在于一个精确到读写 一个只能精确到协程对吗

    作者回复: 第一个问题 对。第二个问题太过笼统所以没法回答,当然文章中已经介绍读写锁的功能,适合写少读多的场景

    
    1
  • David
    2021-01-04
    func (rw *RWMutex) RLock() { if atomic.AddInt32(&rw.readerCount, 1) < 0 { // rw.readerCount是负值的时候,意味着此时有writer等待请求锁,因为writer优先级高,所以把后来的reader阻塞休眠 runtime_SemacquireMutex(&rw.readerSem, false, 0) } } 这个代码, rw.readerCount 为负数,表示有writer,正在等待,则reader要进行休眠。 func (rw *RWMutex) Lock() { // 首先解决其他writer竞争问题 rw.w.Lock() // 反转readerCount,告诉reader有writer竞争锁 r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders // 如果当前有reader持有锁,那么需要等待 if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 { runtime_SemacquireMutex(&rw.writerSem, false, 0) } } 这里是先获取到了锁,才去修改 rw.readerCount 的值,也就是说 每个writer 只有在获取到锁的情况下,才去把 rw.readerCount改成负数,而读锁是否休眠,也是根据这个值来判断。 func (rw *RWMutex) Unlock() { // 告诉reader没有活跃的writer了 r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders) // 唤醒阻塞的reader们 for i := 0; i < int(r); i++ { runtime_Semrelease(&rw.readerSem, false, 0) } // 释放内部的互斥锁 rw.w.Unlock() } 而这个地方 先去释放了 reader,再去释放阻塞的writer 假设一种情况,在lock的时候,先后有a,b两个writer 进来,发现还有其他的reader正在使用,那么a,b进行阻塞,当reader 使用完了后,唤醒了a,a获取到了锁,在a使用期间,也有多个reader 进来,进行的休眠。当a使用完成后,调用unlock方法,先是修改了rw.readerCount(根据rlock的方法,rw.readerCount是唯一判断,是否阻塞的条件,那么,当这个时候,有新的reader进来,就可以无条件使用了);再去唤醒被阻塞的reader(这个情况下,唤醒的reader 也可以进行无条件使用了),最后去释放锁,唤醒了b,b去获取锁的时候,发现有reader在使用,修改rw.readerCount的值(标示有等待的writer),然后进行休眠,当最后一个reader使用完成后,唤醒b,这个时候b才正在获取到了锁。 按照以上逻辑,多个writer的情况下,并没有造成reader出现饥饿状态,反而在释放写锁的那一刹那,新的reader 占了先机,这种情况怎么叫 Write-preferring 方案。我理解的Write-preferring 方案:是只有在没有writer的情况下,才轮到reader执行,多个writer的情况,是一个writer一个writer执行完,才会执行reader。我从代码中看出了不明白的地方,希望老师 帮忙解答一下
    展开

    作者回复: 在readers已占有锁的情况下,后续只要有writer存在,会优先writer执行锁,后续的reader需要writer释放锁才可以获取

    共 4 条评论
    1
  • 50%
    2020-11-07
    r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders 这句老师看我理解的对么。首先前一步反转操作是用原子操作实现的,此时其他的reader可能会改变readerCount字段的状态。虽然看起来加减同一个rwmutexMaxReaders看似结果相等,但在并发的场景下,其他reader读到的readerCount的状态为负值,表示有写锁的情况存在。

    作者回复: 对

    
    1
  • john-jy
    2023-06-07 来自北京
    没人发现factorial退出条件是错误的吗?

    作者回复: 👍🏻😁是的, 改成n=1

    
    
  • Traveller
    2023-04-27 来自上海
    第二种死锁的场景有点隐蔽。我们知道,有活跃 reader 的时候,writer 会等待,如果我们在 reader 的读操作时调用 writer 的写操作(它会调用 Lock 方法),那么,这个 reader 和 writer 就会形成互相依赖的死锁状态。Reader 想等待 writer 完成后再释放锁,而 writer 需要这个 reader 释放锁之后,才能不阻塞地继续执行。这是一个读写锁常见的死锁场景。 这是什么意思?完全看不懂

    作者回复: 在同一个goroutine中,先调用读锁,再调用写锁,会导致死锁

    
    
  • 极客酱酱
    2022-04-19
    鸟窝老师,麻烦问一下您这边使用的脑图工具是哪个,我正在学习这种用脑图梳理知识点的方法,手头的工具不太友好,手动狗头。

    作者回复: processon

    
    
  • 8.13.3.27.30
    2021-11-27
    有一个问题、写错unlock逻辑中、解锁之前会唤醒所有等待读的锁、但是再锁的过程当中并可能会继续来读和写的操作、这些操作这里貌似并不能保证写锁的优先,因为写锁解锁的过程会把后来的读锁也唤醒、而这个时候后来的写锁(但是它先于后来的读锁操作锁)没有办法优先后来的读锁获取到锁,不知道理解是否正确,另外读写锁的实现看上去在极限情况下会导致写饥饿、当然也可能是读饥饿(理论上这种情况不应该使用读写锁)、请教老师我的理解是否正确,如果正确怎么解决写饥饿的问题

    作者回复: 很好的发现,你说的对

    
    
  • 🐭
    2021-08-06
    第一个例子中,写操作在主携程里,为什么还要加锁

    作者回复: 嗯,这个例子不太好,应该用两个writer更好理解

    
    