状态,恢复本地中断,并获释放旋锁。
使用自旋锁,需要注意:
1. 使用自旋锁的临界区必定不能进入休眠。自旋锁被成功获取后,内核会停用抢占机
制。假如现在有个临界区 A 获取了自旋锁,然后进入休眠主动放弃了 CPU 使用权,线程 B
开始运行。线程 B 的临界区也想访问共享数据,但是自旋锁已被占用,B 线程的临界区就一
直处于等待自旋锁的状态,而此时内核抢占被禁止,临界区 A 无法获得主动权释放锁,从
而发生了死锁。
2.临界区内要避免中断抢占。假设现在有线程获取了自旋锁,在释放之前,被中断抢占
了,如果中断也需要获取共享数据,也去申请自旋锁,那中断就会进入等待状态,那就大事
不妙了,直接死锁。这里要避免终端抢占的办法,就是使用上面介绍的 spin_lock_irq 函数和
spin_lock_irqsave 函数来申请自旋锁,禁用本地中断。
3.临界区要尽量短。原因上面有解释过了。
使用示例:
1. spinlock_t lock;
2. spin_lock (&gpioled.lock); //上锁
3. /* 临界区 */
4. spin_unlock (&gpioled.lock); //解锁
上锁和解锁中间就是临界区。
5.3.3 信号量
与自旋锁相比,信号量有两个优势:
1.信号量可以让等待信号量的线程进入休眠,减少 CPU 的占用;
2.信号量支持对个线程同时访问共享资源。
信号量结构体定义如下:
1. struct semaphore {
2. raw_spinlock_t lock;
3. unsigned int count;
4. struct list_head wait_list;
5. };
元素 count 即指信号量支持同时访问共享资源的线程数。
常用的信号量接口函数有:
void sema_init(struct semaphore *sem, int val) :初始化信号量,设置信号值(同时访问
个数)为 val。
void down(struct semaphore *sem) :获取信号量,失败时会进入休眠且不可以被信号
打断,不能用于中断。
int down_trylock(struct semaphore *sem) :获取信号量,不会进入休眠,成功返回 0。
int down_interruptible(struct semaphore *sem) :获取信号量,失败时会进入休眠但可
以被信号打断,不能用于中断,休眠被打断时返非 0 值。
void up(struct semaphore *sem) :释放信号量。