欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

xv6的sleep和wakeup

程序员文章站 2022-06-19 13:54:02
...

其实实现了一种管程

xv6的锁,用的时候都是acquire和release包起来,保证互斥。中间可以sleep,睡觉过程中,放弃锁,别人可以进入临界区。醒来又要获得锁(因为又重新进入临界区了)。
wakeup和Semaphore的signal()操作不一样,不会累计唤醒次数。如果此刻没有进程在等这个chan,就什么也不做。
综上,实际上sleep-lock在这里,相当于实现了一个Brinch Hansen(1975)的monitor。
也就是访问临界区的过程要互斥,唤醒操作必须是管程过程的最后一句。

sleep函数

sleep(void *chan, struct spinlock *lk)
第一个参数chan并不一定要用什么,只要你释放掉当前持有的spinlock (这里是q->lock)就可以。这里chan直接用q,只是方便,不是必须的。

NetBSD

其实在别的操作系统上,是用mutexconditional variable实现的。比如NetBSD。
参见:https://netbsd.gw.com/cgi-bin/man-cgi?condvar+9+NetBSD-current
pthread也提供了类似的原语。

疑问

xv6有两套锁的原语(primitives),一套是acquire/release,就是spinlock。
另一套是acquiresleep/relasesleep。这里与sleep配合使用的,竟然是普通的spinlock。
这就意味着如果多个进程要抢这个锁,其他进程要忙等,而不是去睡觉。
我以为sleep一定要配合sleep版的acquire和release使用。

xv6源码

400 struct q {
401   struct spinlock lock;
402   void *ptr;
403 };
404
405 void*
406 send(struct q *q, void *p)
407 {
408   acquire(&q->lock);
409   while(q->ptr != 0)
410     ;
411   q->ptr = p;
412   wakeup(q);
413   release(&q->lock);
414 }
415
416 void*
417 recv(struct q *q)
418 {
419   void *p;
420
421   acquire(&q->lock);
422   while((p = q->ptr) == 0)
423     sleep(q, &q->lock);
424   q->ptr = 0;
425   release(&q->lock);
426   return p;
427 }
相关标签: xv6 同步