• Qfeng
    置顶
    2022-03-29
    回答思考题:Linux 的读写锁,因为每次读锁加锁计数-1,所以最多支持0x01000000个进程并发读取共享数据。 这样的读写锁的不足:读或者写锁拿不到时忙等,可以优化成trylock,拿不到可以先干其他的,等一段时间再尝试拿锁。(不知道回答的对不对) 感悟:不论是单值信号量还是多值信号量,亦或是原始自旋锁、trylock版本自旋锁还是读写锁,各种机制的设计和优化都是为了资源(CPU等)的更合理更高效的使用而优化。互斥机制有很多,理解每种锁机制重要,但是理解我们的业务更重要,这样才能因地制宜选择合适的锁。 老师简明扼要,点到即止的文风太赞了,谢谢。

    作者回复: 是的

    共 2 条评论
    5
  • springXu
    置顶
    2021-05-30
    同步与锁 操作系统是让应用程序认为当前有超大的内存空间和强大的cpu来工作的硬件环境,但其实硬件没有这么强大。那如何解决呢?比如在单核cpu上可以用分时技术,让进程交替执行。对于一个进程来说,我们可以把一个进程变成了多个线程来执行。但这样就产生了同一个资源可以是内存的某一具体地址,可以是鼠标可以是磁盘上的某一文件被多个线程访问和修改的问题。这两节课提供了解决思路,一个是cosmos操作系统的方案,一个是linux的方案。 1.原子性。就是硬件执行指令时不被打断。对于x86是复杂指令集。一条指令可以做读修改内存值的操作,指令集中直接支持锁定操作。对于精简指令集,就相对麻烦些,硬件会提供bitband的操作。 2.中断控制是在执行时,防止中断信号突然来了把当前执行的过程打断了。 解决方法就是关闭中断。让中断信号等到可以通知时,才发起通知。 3.自旋锁。在多核的cpu环境下,当前核心的cpu要访问的资源是有可能被其他核的cpu来访问的。如果产生这种情况,那就让其他核的cpu自己执行空转。一直到当前核心的cpu把访问资源让出后,其他核的cpu通过检测到了可以访问资源,不在空转执行相关操作恢复正常运行。而这个过程就是自旋锁。这里会有一点浪费cpu的运行效率。毕竟有个cpu在空转。当空转时间过长时,浪费的效能更大。我们需要更好的利用cpu核的方式来解决这个问题。那就是互斥。 4.信号量 对于单一资源的信号量也可以说是互斥锁。 互斥锁和自旋锁的区别就是原来那个空转的核不再空转,而是把当前运行的线程或者进程睡眠去执行其他的线程或者进程了。 当资源被适当后,去通知睡眠线程或者进程。这就是信号量。linux下新版本的信号量在被移除。
    展开

    作者回复: 你好,铁子总结 到位

    共 3 条评论
    18
  • 老男孩
    置顶
    2021-05-28
    这个排队自旋锁的实现方式感觉很风骚啊。关于读锁最大支持进程数是0x01000000(学友们都已经解答了)关于写饥饿的问题,既然写锁和读锁在同时获取锁状态时候写锁优先,那么就应该对读锁做一个限制,不能让读锁朝着最大数奔去。比如,系统检测到有写锁在等待,那么就限制新的读锁加入,等已经存在的读锁都释放了,写锁马上加锁更新资源。然后等待的读锁再开始加锁读取。这个等待的队列要分为读锁队列和写锁队列。优先处理写锁队列,在没有写锁的时候才能继续加读锁,如果有写锁等待,那么新的读锁不管超没超出那个最大数,都要进入读锁队列等待写锁完成后再开始自己的表演。

    作者回复: 嗯嗯见解独到

    共 4 条评论
    34
  • pedro
    2021-05-28
    以后我就是第一东吹了😁! 像这样的清晰明了,言简意赅的Linux内核源码解读实在是太少了,这样的文章读起来实在是太爽了,强烈小编安排一下东哥的下一个专栏叫做 《纵览Linux源码,小白也能学透》。 对于思考题答案,读并发进程的最大个数就是0x01000000,只要lock大于0都是可以共享数据的。 至于读写锁的不足,我个人觉得最不友好的点在于读写互斥上,由于读锁对写锁是互斥的,如果一直有人读,那么计数器一直小于0x01000000,加写锁时也一直小于0,写锁一直也不会成功,会陷入长时间的写饥饿状态,并且一直自旋,浪费CPU资源。 所以改进点就在于,给写进程配上一个休眠队列,待加锁失败进入队列休眠等待,待解读锁时判断计数器,决定是否唤醒队列中的写进程。 当然还有很多其它的优化点,欢迎大家集思广益~

    作者回复: 哈哈 欢迎

    共 2 条评论
    29
  • blentle
    2021-05-28
    回答一下思考题 1.理论上可以支持x01000000这么多进程,但实际上受限于文件句炳也就是文件描述符的限制,还有考虑多个线程的问题等等,注定最终远远小于这个值 2.读写锁造成写饥饿的情况是不是可以参考jdk的读写锁的实现,在条件等待队列中判断队列第一个元素是不是一个写进程,如果是写进程,让其直接优先获取锁.

    作者回复: 嗯嗯

    
    15
  • GeekYanger
    2021-12-13
    文中: “//Linux没有这样的结构,这只是为了描述方便 typedef struct raw_spinlock { union { unsigned int slock;//真正的锁值变量 u16 owner; u16 next; } }raw_spinlock_t;” 这里老师为了帮助我们理解汇编代码构造了一个这样的结构体,我觉得,这个owner和next要被包在一个struct中才是老师想要表述的意思,不然owner和next的取值是一样的,都是低16位。

    作者回复: 对 对 对 我大意了

    共 3 条评论
    5
  • 子青
    2021-09-23
    老师,我有两个问题想请教 1 。Linux自旋锁,如果一个进程在获取锁之后挂了怎么办,没人给owner +1了,后面排队的进程岂不是永远等不到锁释放? 2。信号量那里,down是在链表的头部插入,up是唤醒链表的头部,这样不会有饥饿问题吗,链表后面的可能永远拿不到资源?

    作者回复: 1.进程调用自旋锁,是在内核态运行的内核代码,如果在这个代码路径上挂了,那就说明内核有BUG 需要修正 2. up之后会对进程的优先级进行处理的,不会后面的进程没机会的

    共 2 条评论
    4
  • Geek_8c4220
    2021-06-09
    为什么这节里实现自旋锁的时候都没有关中断了呢?

    作者回复: 因为我没有讲

    
    4
  • doos
    2022-04-21
    感觉不学习汇编和c很多都看不懂

    编辑回复: 看你的目的,为了理解这门课,很多内容可以现搜的。汇编到初始化那里,后面都是C。具体有啥不懂之处,你可以再留言提问。

    
    3
  • 疯码
    2022-01-18
    请问下为什么保存和恢复eflags那段代码用push pop而不是mov呢

    作者回复: eflags寄存器不能使用mov指令访问

    
    3