xv6的sleep和wakeup

其实实现了一种管程

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 }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值