大部分竞态可通过使用内核的并发控制原语,并应用几个基本的原理来避免。第一个规则是,只要可能,就应该避免资源的共享,这种思想的明显应用就是避免使用全局变量。但硬件资源本质上就是共享的,软件资源经常需要对其他执行线程可用。全局变量并不是共享数据的唯一途径,只要我们的代码将一个指针传递给了内核的其他部分,一个新的共享就可能建立。在单个执行线程之外共享硬件或软件资源的任何时候,因为另外一个线程可能产生对该资源的不一致观察,因此必须显示地管理对该资源的访问。访问管理的常见技术是“锁定”或“互斥”----确保一次只有一个执行线程可操作共享资源。
临界区:在任意给定的时刻,代码只能被一个线程执行。并不是所有的林汲取都是一样的,因此内核为不同的需求提供了不同的原语。
进程休眠:当一个Linux进程到达某个时间点,此时它不能进行任何处理时,它将进入休眠状态,这将把处理器让给其他执行线程直到将来它能够继续完成自己的处理为止。我们可以使用一种锁定机制,当进程在等待临界区的访问时,此机制可让进程进入休眠状态。重要的是,我们将执行另外一个操作,该操作也可能会休眠,因此休眠可能在任何时刻发生。为了让我们的临界区正确工作,我们选择使用的锁定原语必须在其他拥有这个锁并休眠的情况下工作。信号量是一个众所周知的概念,一个信号量本质上是一个整数,它和一对函数联合使用,这一对函数通常称为P和V。希望进入临界区的进程将在相关信号量上调用P;如果信号量的值大于0,则该值会减小1,而进程继续。相反,如果信号量的值为0(或更小),进程必须等待直到其他人释放该信号量。对信号量的解锁通过调用V完成;该函数增加信号量的值,并在必要时唤醒等待的进程。当信号量用于互斥时,信号量的值该初始化为1。
当一个线程成功调用上述down的某个版本后,就称该线程“拥有”了该信号量,这样,该线程就被赋予访问由该信号量包含的临界区的权利。当互斥操作完成后,必须返回该信号量。Linux等价于V的函数是up:void up(struct semaphore *sem);任何拿到信号量的线程都必须通过一次对up调用而释放该信号量。
3.completion
completion是一中轻量级的机制,它允许一个线程告诉另一个线程某个工作已经完成。为了使用completion代码必须包含<linux/completion.h>可利用下面的接口创建completion:DECLART_COMPLETION(my_completion);或者动态地创建和初始化completion,则使用下面的方法:
<三>.自旋锁
LINUX设备驱动程序笔记(四)并发和竞态,布布扣,bubuko.com
原文地址:http://blog.csdn.net/to_be_it_1/article/details/38666319