|
信号量在内核中的定义如下:
struct semaphore {
raw_spinlock_tlock;///自旋锁
unsigned intcount;///count=1时可进行互斥操作
struct list_headwait_list;
}; 信号量的初始化:
sem_init(&sem,val);///var代表信号量的初始值
获取信号量:
down(&sem);若此时信号量为0,则该进程会会处于睡眠状态,因此该函数不可用于中断上下文中。
接下来分析一下获取信号量的源码:
static noinline void __sched __down(struct semaphore *sem)
{
__down_common(sem, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}
static inline int __sched __down_common(struct semaphore *sem, long state,
long timeout)
{
struct task_struct *task = current;
struct semaphore_waiter waiter;
list_add_tail(&waiter.list, &sem->wait_list);
waiter.task = task;
waiter.up = 0;
///死循环
for (;;) {
///如果当前进程被信号唤醒,则退出
if (signal_pending_state(state, task))
goto interrupted;
///如果进程的等待时间超时,则退出
if (timeout <= 0)
goto timed_out;
__set_task_state(task, state);
raw_spin_unlock_irq(&sem->lock);
///在等待队列中等待调度。
timeout = schedule_timeout(timeout);
raw_spin_lock_irq(&sem->lock);
///如果调度是由信号量的释放而唤醒的,则返回0
if (waiter.up)
return 0;
}
......
} 释放信号量
up(&sem);
互斥信号量:
struct mutex {
/* 1: unlocked, 0: locked, negative: locked, possible waiters */
atomic_tcount;
spinlock_twait_lock;
struct list_headwait_list;
......
}; 互斥信号量的初始化:
init_mutex(&sem);
同样作为同步操作,mutex、spinlock、semaphore有如下差异:
1、mutex的count初始化为1,而semaphore则初始化为0
2、mutex的使用者必须为同一线程,即必须成对使用,而semaphore可以由不同的线程执行P.V操作。
3、进程在获取不到信号量的时候执行的是sleep操作,而进程在获取不到自旋锁的时候执行的是忙等待操作。因此,不难看出,如果需要保护的临界区比较小,锁的持有时间比较短的情况下,通常使用spinlock。这样可以不需要对等待锁的进程执行睡眠/唤醒操作,大大节省了cpu时间。因此,spinlock通常作为多处理器之间的同步操作。
|
|
|