本文共 2429 字,大约阅读时间需要 8 分钟。
信号量(Semaphore)是操作系统中常用的同步机制,用于管理进程间的互斥和同步问题。本文将深入探讨信号量的实现原理、初始化方法以及常见的down()/up()操作函数。
信号量由struct semaphore结构体描述,主要成员包括:
信号量还定义了一个与其相关的struct semaphore_waiter结构体,该结构体用于描述等待信号量的进程:
信号量的初始化分为两种:动态初始化和静态定义。两种方式均通过__SEMAPHORE_INITIALIZER()初始化相关成员变量。
#define __SEMAPHORE_INITIALIZER(name, n) { .lock = __RAW_SPIN_LOCK_UNLOCKED((name).lock), .count = n, .wait_list = LIST_HEAD_INIT((name).wait_list),}#define DEFINE_SEMAPHORE(name) struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)static inline void sema_init(struct semaphore *sem, int val) { static struct lock_class_key __key; *sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val); lockdep_init_map(&sem->lock.dep_map, "semaphore->lock", &__key, 0);} 信号量的使用基础上,down()/up()函数对信号量的加锁和解锁操作起着关键作用。
down()的实现主要包括以下步骤:
void down(struct semaphore *sem) { unsigned long flags; raw_spin_lock_irqsave(&sem->lock, flags); if (likely(sem->count > 0)) { sem->count--; } else { __down(sem); } raw_spin_unlock_irqrestore(&sem->lock, flags);} 当信号量.count大于0时,本地加锁并减少count值,表示当前进程已获得信号量。否则,调用__down()进入等待队列。
__down()函数会根据不同的 errno类型调用__down_common(),参数state决定进程进入哪种睡眠状态:
down_interruptible()与down()类似,但进程进入可中断睡眠状态。
down_killable()允许进程在不可中断状态下被唤醒。
down_timeout()是在超时后唤醒的特定实现。
down_trylock()尝试获取锁但不阻塞。
int down_trylock(struct semaphore *sem) { unsigned long flags; int count; raw_spin_lock_irqsave(&sem->lock, flags); count = sem->count - 1; if (likely(count >= 0)) { sem->count = count; } raw_spin_unlock_irqrestore(&sem->lock, flags); return (count < 0);} up()函数的实现相对简单:
void up(struct semaphore *sem) { unsigned long flags; raw_spin_lock_irqsave(&sem->lock, flags); if (list_empty(&sem->wait_list)) { sem->count++; } else { __up(sem); } raw_spin_unlock_irqrestore(&sem->lock, flags);} spinlock和信号量都是同步机制,但主要区别如下:
转载地址:http://fpoqz.baihongyu.com/