【驱动】同步、互斥、阻塞

1. 原子操作
原子操作指的是在执行过程中不会被别的代码路径所中断的操作。
常用原子操作函数举例:
atomic_t v = ATOMIC_INIT(0); //定义原子变量v并初始化为0
atomic_read(atomic_t *v); //返回原子变量的值
void atomic_inc(atomic_t *v); //原子变量增加1
void atomic_dec(atomic_t *v); //原子变量减少1
int atomic_dec_and_test(atomic_t *v); //自减操作后测试其是否为0,为0则返回true,否则返回false。

2. 信号量
信号量(semaphore)是用于保护临界区的一种常用方法,只有得到信号量的进程才能执行临界区代码。
当获取不到信号量时,进程进入休眠等待状态,即当持有信号量时,(进程)是可以休眠的。休眠(同时交出CPU使用权),使得CPU得到最大限度的利用。

  定义信号量
  struct semaphore sem;
  初始化信号量
  void sema_init (struct semaphore *sem, int val);
  void init_MUTEX(struct semaphore *sem);//初始化为0

以上三句指令等价于:

  static DECLARE_MUTEX(button_lock); //定义互斥锁

获得信号量
void down(struct semaphore * sem);
int down_interruptible(struct semaphore * sem);
int down_trylock(struct semaphore * sem);
释放信号量
void up(struct semaphore * sem);

问题1:互斥锁是一种特殊的信号量?

 

3. 阻塞
阻塞操作
是指在执行设备操作时若不能获得资源则挂起进程,直到满足可操作的条件后再进行操作。
被挂起的进程进入休眠状态,被从调度器的运行队列移走,直到等待的条件被满足。

非阻塞操作
进程在不能进行设备操作时并不挂起,它或者放弃,或者不停地查询,直至可以进行操作为止。

fd = open("...", O_RDWR | O_NONBLOCK);

 

 

 

在TP驱动定义一个信号量互斥锁DECLARE_MUTEX(xx_lock), //等同struct semaphore xx_lock; init_MUTEX(&xx_lock);之和;
xx_open()中down(&xx_lock)获取信号量,
在xx_close()中up(&xx_lock)释放信号量。

fd = open("/dev/keys_10", O_RDWR);则默认为阻塞操作。


DECLARE_MUTEX宏

Linux可以使用互斥信号量来表示互斥锁,那就是通过宏DECLARE_MUTEX来定义一个互斥信号量,因为DECLARE_MUTEX这个宏,

Marcin Slusarz在08年提交的了一个patch,邮件地址为:https://lkml.org/lkml/2008/10/26/74,Marcin Slusarz认为DECLARE_MUTEX宏会误导开发者,所以建议将DECLARE_MUTEX修改成DEFINE_SEMAPHORE,这个提议最终被内核社区所接受,在2.6.36版本后的内核就没有DECLARE_MUTEX这个宏了,取而代之的是DEFINE_SEMAPHORE宏,在后来同互斥信号量相关的init_MUTEX、init_MUTEX_LOCKED也从文件中移除了。

————————————————
版权声明:本文为CSDN博主「Zackary-」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/WANG__RONGWEI/article/details/52832652


自旋锁:

自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,此即"自旋锁"。

跟互斥锁一样,一个执行单元要想访问被自旋锁保护的共享资源,必须先得到锁,在访问完共享资源后,必须释放锁。如果在获取自旋锁时,没有任何执行单元保持该锁,那么将立即得到锁;如果在获取自旋锁时锁已经有保持者,那么获取锁操作将自旋在那里,直到该自旋锁的保持者释放了锁。由此我们可以看出,自旋锁是一种比较低级的保护数据结构或代码片段的原始方式,这种锁可能存在两个问题:死锁、过多占用cpu资源。

 
信号量、互斥锁、自旋锁的使用区别:
由此可见,自旋锁比较适用于锁使用者保持锁时间比较短的情况。正是由于自旋锁使用者一般保持锁时间非常短,因此选择自旋而不是睡眠是非常必要的,自旋锁的效率远高于 互斥锁。 信号量和读写信号量适合于保持时间较长的情况,它们会导致调用者睡眠,因此只能在 进程上下文使用,而自旋锁适合于保持时间非常短的情况,它可以在任何上下文使用。如果被保护的 共享资源只在进程上下文访问,使用信号量保护该共享资源非常合适,如果对共享资源的访问时间非常短,自旋锁也可以。但是如果被保护的共享资源需要在中断上下文访问(包括底半部即 中断处理句柄和顶半部即 软中断),就必须使用自旋锁。自旋锁保持期间是抢占失效的,而信号量和读写信号量保持期间是可以被抢占的。自旋锁只有在 内核可抢占或 SMP(多处理器)的情况下才真正需要,在单CPU且不可抢占的内核下,自旋锁的所有操作都是空操作。
 

自旋锁和信号量的使用要点:
(1)自旋锁不能递归
(2)自旋锁可以用在中断上下文(信号量不可以,因为可能睡眠),但是在中断上下文中获取自旋锁之前要先禁用本地中断

  注:中断上下文是不参与进程调度的。
(3)自旋锁的核心要求是:拥有自旋锁的代码必须不能睡眠,要一直持有CPU直到释放自旋锁
(4)信号量和读写信号量适合于保持时间较长的情况,它们会导致调用者睡眠,因此只能在进程上下文使用,而自旋锁适合于保持时间非常短的情况,它可以在任何上下文使用。
如果被保护的共享资源只在进程上下文访问,使用信号量保护该共享资源非常合适,如果对共享资源的访问时间非常短,自旋锁也可以。但是如果被保护的共享资源需要在中断上下文访问(包括底半部即中断处理句柄和顶半部即软中断),就必须使用自旋锁。自旋锁保持期间是抢占失效的,而信号量和读写信号量保持期间是可以被抢占的。自旋锁只有在内核可抢占或SMP(多处理器)的情况下才真正需要,在单CPU且不可抢占的内核下,自旋锁的所有操作都是空操作。

你可能感兴趣的:(【驱动】同步、互斥、阻塞)