目录
1.在lock中我们要做什么
2.spinlock和wait channel是什么
2.1spinlock(自旋锁)
2.2wait channel
3.实现(1.semaphore 2.wait channel)
3.1.lock_acquire
3.2.lock_release
3.3.lock_create
3.4lock_destroy
3.5.lock_do_i_hold
简单地说,如果有线程获取了lock 我们就不再获取,如果没线程拿到了lock,那么我们就要获取。
与semaphore不同的是,lock是有“拥有者”的概念的,想要释放(lock_release)必须要先通过lock_acquire获取到,并且目前是这个lock的拥有者。
struct lock {
char *lk_name;
HANGMAN_LOCKABLE(lk_hangman); /* Deadlock detector hook. */
// add what you need here
// (don't forget to mark things volatile as needed)
#if OPT_SYNCH
#if USE_SEMAPHORE_FOR_LOCK
//1.semaphore实现lock
struct semaphore *lk_sem;
#else
//2.wait channel实现
struct wchan *lk_wchan;
#endif
struct spinlock lk_lock;
volatile struct thread *lk_owner; //拥有者
#endif
};
对此有两种实现方式:
1.使用semaphore(通过spinlock实现)
2.使用wait channel
所以spinlock 和wait channel是什么,为什么可以实现lock
自旋锁是semaphore的实现方式,当使用spinlock_acquire以及spinlock_release包裹起来,便会使其成为临界区,其他想进入临界区的进程就会通过轮询(spin)的方式,不断的询问是否可以获取资源,是一种忙等(busy waiting)的状态,也就是始终处于CPU的执行态(Running)。
显然这会造成CPU资源的浪费(主要缺点)。但当处于频繁使用但等待的时间很短的情况时,spinlock就会是一种很有效的方式,因为避免了切换进程(上下文切换)耗费大量时间。
自旋锁通常用于多处理器的系统。
wait channel 是一种非忙等的方式,通过sleep阻塞进程,退出CPU,等待唤醒,可以理解为让权锁。
void
lock_acquire(struct lock *lock)
{
/* Call this (atomically) before waiting for a lock */
//HANGMAN_WAIT(&curthread->t_hangman, &lock->lk_hangman);
// Write this
KASSERT(lock != NULL);
if (lock_do_i_hold(lock)) {//当前线程已经获取到lock了
kprintf("AAACKK!\n");
}
KASSERT(!(lock_do_i_hold(lock))); //lock_do_i_hold(lock)判断lock的owner是否是当前线程
KASSERT(curthread->t_in_interrupt == false);
// 1.用semaphore实现
#if USE_SEMAPHORE_FOR_LOCK
P(lock->lk_sem);
spinlock_acquire(&lock->lk_lock); //需要用spinlock保护查看当前是否有人拿到lock
#else
//2.wait channel实现
spinlock_acquire(&lock->lk_lock); //spinlock在这里为了保证原子性
while (lock->lk_owner != NULL) { //true:当前有人有lock
wchan_sleep(lock->lk_wchan, &lock->lk_lock); //优化版的,避免了busy waiting
}
#endif
KASSERT(lock->lk_owner == NULL); //当前没人占有 lock,我就拿
lock->lk_owner=curthread;
spinlock_release(&lock->lk_lock); //需要用spinlock保护查看当前是否有人拿到lock
//——————————————————————————————————————————————————————————————
(void)lock; // suppress warning until code gets written
/* Call this (atomically) once the lock is acquired */
//HANGMAN_ACQUIRE(&curthread->t_hangman, &lock->lk_hangman);
}
void
lock_release(struct lock *lock)
{
// Write this
#if OPT_SYNCH
KASSERT(lock != NULL); //当前有人获得lock了
KASSERT(lock_do_i_hold(lock));//当前线程是lock的owner
spinlock_acquire(&lock->lk_lock);
lock->lk_owner=NULL;
//1. semaphore实现
#if USE_SEMAPHORE_FOR_LOCK
V(lock->lk_sem); //直接使用V操作
#else
//2. wait channel实现
wchan_wakeone(lock->lk_wchan, &lock->lk_lock); //唤醒
#endif
spinlock_release(&lock->lk_lock);
#endif
(void)lock; // suppress warning until code gets written
}
struct lock *
lock_create(const char *name)
{
struct lock *lock;
lock = kmalloc(sizeof(*lock));
if (lock == NULL) {
return NULL;
}
lock->lk_name = kstrdup(name);
if (lock->lk_name == NULL) {
kfree(lock);
return NULL;
}
HANGMAN_LOCKABLEINIT(&lock->lk_hangman, lock->lk_name);
// add stuff here as needed
#if OPT_SYNCH
#if USE_SEMAPHORE_FOR_LOCK
//1.semaphore方式
lock->lk_sem = sem_create(lock->lk_name,1);//直接创建一个semaphore
if (lock->lk_sem == NULL) {
#else
//2.wait channel
lock->lk_wchan = wchan_create(lock->lk_name);//直接蒋健一个wait channel
if (lock->lk_wchan == NULL) {
#endif
kfree(lock->lk_name);
kfree(lock);
return NULL;
}
lock->lk_owner = NULL;
spinlock_init(&lock->lk_lock);
#endif
return lock;
}
void
lock_destroy(struct lock *lock)
{
KASSERT(lock != NULL);
// add stuff here as needed
#if OPT_SYNCH
spinlock_cleanup(&lock->lk_lock);
#if USE_SEMAPHORE_FOR_LOCK
//1.
sem_destroy(lock->lk_sem);
#else
//2.
wchan_destroy(lock->lk_wchan);
#endif
#endif
kfree(lock->lk_name);
kfree(lock);
}
bool
lock_do_i_hold(struct lock *lock) //判断这个lock的owner是否是当前线程
{
// Write this
#if OPT_SYNCH
bool res;
spinlock_acquire(&lock->lk_lock);
res = lock->lk_owner == curthread;
spinlock_release(&lock->lk_lock);
return res;
#endif
(void)lock; // suppress warning until code gets written
return true; // dummy until code gets written
}