XV6——锁与并发
在操作系统中,什么情况下会导致并发?
- 多线程
- 多处理器
- 中断
Xv6不支持多线程,但其他两种情况确实会在Xv6中发生。为了解决并发问题,需要一种机制:锁
Xv6中实现了两种锁:自旋锁和睡眠锁
自选锁
// Mutual exclusion lock.
struct spinlock
{uint locked; // Is the lock held?// For debugging:char *name; // Name of lock.struct cpu *cpu; // The cpu holding the lock.
};
最核心的字段是locked
- 当locked == 0,说明无锁,可以访问
- 当locked == 1,说明已经上锁,无法访问
加锁
// Acquire the lock.
// Loops (spins) until the lock is acquired.
void acquire(struct spinlock *lk)
{push_off(); // disable interrupts to avoid deadlock.if (holding(lk))panic("acquire");// On RISC-V, sync_lock_test_and_set turns into an atomic swap:// a5 = 1// s1 = &lk->locked// amoswap.w.aq a5, a5, (s1)while (__sync_lock_test_and_set(&lk->locked, 1) != 0);// Tell the C compiler and the processor to not move loads or stores// past this point, to ensure that the critical section's memory// references happen strictly after the lock is acquired.// On RISC-V, this emits a fence instruction.__sync_synchronize();// Record info about lock acquisition for holding() and debugging.lk->cpu = mycpu();
}
加锁过程可以拆分为4步:
- 关中断
- 获取锁
- 设置内存屏障
- 更新数据
解锁
// Release the lock.
void release(struct spinlock *lk)
{if (!holding(lk))panic("release");lk->cpu = 0;// Tell the C compiler and the CPU to not move loads or stores// past this point, to ensure that all the stores in the critical// section are visible to other CPUs before the lock is released,// and that loads in the critical section occur strictly before// the lock is released.// On RISC-V, this emits a fence instruction.__sync_synchronize();// Release the lock, equivalent to lk->locked = 0.// This code doesn't use a C assignment, since the C standard// implies that an assignment might be implemented with// multiple store instructions.// On RISC-V, sync_lock_release turns into an atomic swap:// s1 = &lk->locked// amoswap.w zero, zero, (s1)__sync_lock_release(&lk->locked);pop_off();
}
解锁过程与加锁过程相反:
- 重置数据
- 设置内存屏障
- 释放锁
- 开中断
关中断
void push_off(void)
{int old = intr_get();intr_off();if (mycpu()->noff == 0)mycpu()->intena = old;mycpu()->noff += 1;
}