1.原子操作与自旋锁的区别:
1)原子操作只能对整形变量或者位进行保护,但是,在实际的使用环境中怎么可能只有整形
变量或位这么简单的临界区。
2)设备结构体变量就不是整型变量,我们对于结构体中成员变量的操作也要保证原子性,在线程 A 对结构体变量使用期间,应该禁止其他的线程来访问此结构体变量,这些工作原子操作都不能胜任,需要本节要讲的锁机制,在 Linux内核中就是自旋锁。
2.当一个线程要访问某个共享资源的时候首先要先获取相应的锁, 锁只能被一个线程持有,
只要此线程不释放持有的锁,那么其他的线程就不能获取此锁。
对于自旋锁而言,如果自旋锁正在被线程 A 持有,线程 B 想要获取自旋锁,那么线程 B 就会处于忙循环-旋转-等待状态,线程 B 不会进入休眠状态或者说去做其他的处理,而是会一直傻傻的在那里“转圈圈”的等待锁可用。
3.例子:把自旋锁比作一个变量 a,变量 a=1 的时候表示共享资源可用,当 a=0的时候表示共享资源不可用。现在线程 A 要访问共享资源,发现 a=0(自旋锁被其他线程持有),那么线程 A 就会不断的查询 a 的值,直到 a=1。
4.从这里我们可以看到自旋锁的一个缺点:那就等待自旋锁的线程会一直处于自旋状态,这样会浪费处理器时间,降低系统性能,所以自旋锁的持有时间不能太长。所以自旋锁适用于短时期的轻量级加锁,如果遇到需要长时间持有锁的场景那就需要换其他的方法了。
5.使用
5.1包含头文件:
#include <linux/atomic.h>
5.2定义一个自旋锁变量
spinlock_t lock;
5.3 初始化自选锁
spin_lock_init(&gpioled.lock);
5.4使用自旋锁
线程a:
spin_lock_irqsave(&lock, flags) /* 获取锁 */
/* 临界区 */
spin_unlock_irqrestore(&lock, flags) /* 释放锁 */
线程b:
spin_lock_irqsave(&lock, flags) /* 获取锁 */
/* 临界区 */
spin_unlock_irqrestore(&lock, flags) /* 释放锁 */