[OS161] lock的实现(lock_create(), lock_destroy(), lock_acquire(), lock_release(), lock_do_i_hold())

目录

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


1.在lock中我们要做什么

简单地说,如果有线程获取了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

2.spinlock和wait channel是什么

所以spinlock 和wait channel是什么,为什么可以实现lock

    2.1spinlock(自旋锁)

      自旋锁是semaphore的实现方式,当使用spinlock_acquire以及spinlock_release包裹起来,便会使其成为临界区,其他想进入临界区的进程就会通过轮询(spin)的方式,不断的询问是否可以获取资源,是一种忙等(busy waiting)的状态,也就是始终处于CPU的执行态(Running)。

[OS161] lock的实现(lock_create(), lock_destroy(), lock_acquire(), lock_release(), lock_do_i_hold())_第1张图片

      显然这会造成CPU资源的浪费(主要缺点)。但当处于频繁使用但等待的时间很短的情况时,spinlock就会是一种很有效的方式,因为避免了切换进程(上下文切换)耗费大量时间。

      自旋锁通常用于多处理器的系统。

    2.2wait channel

     wait channel 是一种非忙等的方式,通过sleep阻塞进程,退出CPU,等待唤醒,可以理解为让权锁。

3.实现(1.semaphore  2.wait channel)

     3.1.lock_acquire

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);
}

     3.2.lock_release

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
}

     3.3.lock_create

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;
}

     3.4lock_destroy

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);
}

     3.5.lock_do_i_hold

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
}

你可能感兴趣的:(os161,linux,unix,os161,os)