Linux device drives 5(并发与竟态)

原创 2012年03月24日 00:03:15

竟态会导致对共享数据的非控制访问。发生这种错误模式的访问,会产生非预期结果。

内核提供了许多可延迟代码执行的机制,比如workqueue(工作队列)、tasklet(小任务)、以及timer(定时器),而且内核代码可以是抢占式的。对于竟态的发生时很有可能的,虽然竟态一般都是小概率时间,但是带来的危害却很大。

对于这种竟态问题,只要有可能就应该避免资源的共享。

处理并发和竟态的办法就是把这个共享的数据变成原子操作,仅有一个进程来执行。信号量就出来了。一个信号量就是一个整数值,它和一对函数联合使用。这一对函数通常称为P和V操作,希望进入临界区的进程竟在相关的信号量上调用P操作,如果信号量大于0,则该值会减小1,而进程可以继续,相反如果信号量值为0(或更小),进程必须等待直到其他进程来释放信号量。对信号量进行解锁通过调用V操作,该函数增加信号量的值,并在必要时唤醒等待的进程。

信号量用于互斥时候,它的值应该初始化为1,表明仅仅有一个进程能够访问,共享单一访问,就成了互斥,一定要区别 互斥和信号量的概念。

 

信号量和互斥体

Linux内核支持信号量的实现。内核代码必须包含<asm/semaphore.h>相关的类型是struct semaphore

/*
*      初始化信号量函数
*      @param sem 需要初始化的信号量指针
*      @param val 把信号量初始化的初始化值
*      返回值是void
*/
voidsemaphore_init(struct semaphore *sem, int val)
初始化互斥体
DECLARE_MUTEX(name);//初始化一个互斥体
DECLARE_MUTEX_LOCKED(name);//该互斥体处于锁定状态
P操作函数
void down(strcutsemaphore *sema);       //    不可中断
intdown_interruptible(struct semaphore *sema);//可被中断
intdown_trylock(struct semaphore *sema); //如果不能获得就会立即返回一个非0值
Linux 的V操作(释放信号量)
void up(structsemaphore *sema);

正确使用锁的机制是①明确要保护的资源②确保每一个对这些资源的访问使用正确的锁定

读写信号量

一些任务只需要读取受保护的数据结构,而其他的的必须要做出修改。Linux内核提供了一种特殊的信号量,称为rwsem(读写信号量),使用rwsem的代码必须包含 <linux/rwsem.h>

void init_rwsem(structrw_semaphore *sema);//初始化信号量
读取借口
voiddown_read(struct rw_semaphore *sema);
intdown_read_trylock(struct rw_semaphore *sema);
voidup_read(struct rw_semaphore *sema);
读写信号量对于读操作可以共享
voiddown_write(struct rw_semaphore *sema);
intdown_write_trylock(struct rw_semaphore *sema);
void up_write(structrw_semaphore *sema);

一个rw_semaphore可允许一个写入或者无限多个读取者拥有该信号量。写入者的优先级会高些,在写入者完成之前,是不允许读取操作的,这样如果一直有写入者,就会导致读取者一直等待,就是所说的饿死。

completion(完成)接口,completion是一种轻量级的机制,它允许一个线程告诉另外一个线程某个工作已经完成,为了使用completion,代码必须包含<asm/completion.h>

init_completion(strcutcompletion *sema)//初始化一个信号量
voidwait_for_completion(struct completion *c);//等待前一个完成
wait_for_completion是一个非中断的等待。
voidcomplete(struct completion *sema)//完成后通知另外的等待的(阻塞在wait_for_completion)
void complete_all(structcompletion *sema)//通知所有等待该信号量的线程
complete仅仅会唤醒一个线程。而complete_all会唤醒所有等待该信号量的线程

自旋锁

自旋锁可以在不能休眠的代码中执行

完整定义:一个自旋锁是一个互斥设备,他只能有两个值,锁定或者解锁。它通常的实现位某个整数值宏的单个位。希望获得某特定锁的代码测试相关的位。如果锁可以使用,则锁定位被设置,而代码继续进入临界区;相反,如果锁被其他人获得,则代码进入忙循环并重复检查这个锁,知道该锁可用为止,这个循环就是自旋锁的自旋部分。

自旋锁所要包含的文件是<linux/spinlock.h>

spinlock_t mylock= SPIN_LOCK_UNLOCKED;//初始化
voidspin_lock_init(spinlock_t *lock);//动态初始化
voidspin_lock_(spinlock_t *lock);//加锁
voidspin_unlock(spinlock_t *lock);//解锁

适用于自旋锁的核心规则是:任何拥有自旋锁的代码必须都是原子的,它不能睡眠,实际上,它不能因为任何原因放弃处理器

自旋锁和信号量区别

  自旋锁和信号量是解决互斥问题的基本手段,无论是单处理系统还是多处理系统,它们可以不需修改代码地进行移植。那么,这两个手段应该如何选择呢?这就要考虑临界区的性质和系统处理的要求。
    从严格意义上说,信号量和自旋锁属于不同层次的互斥手段,前者的实现有赖于后者。
信 号量是进程级的,用于多个进程之间对资源的互斥,虽然也是在内核中,但是该内核执行路径是以进程的身份,代表进程来争夺资源的。如果竞争不上,会有上下文切换,进程可以去睡眠,但CPU不会停,会接着运行其他的执行路径。从概念上说,这与单CPU或多CPU没有直接的关系,只是在信号量本身的实现上,为了 保证信号量结构存取的原子性,在多CPU中需要自旋锁来互斥。但是值得注意的是上下文切换需要一定时间,并且会使高速缓冲失效,对系统性能影响是很大的。 因此,只有当进程占用资源很长时间时,用信号量才是不错的选择。
   当所要保护的临界区比较短时,用自旋锁是非常方便的,因为它节省上下文切换的时间。但是CPU得不到自旋锁会在那里空转直到锁成功为止,所以要求锁不能在临界区里停留很长时间,否则会降低系统的效率。

   综上,自旋锁是一种保护数据结构或代码片段的原始方式,主要用于SMP中,用于CPU同步,在某个时刻只允许一个进程访问临界区内的代码。它的实现是基于 CPU锁定数据总线的指令。为保证系统效率,自旋锁锁定的临界区一般比较短。在单CPU系统中,使用自旋锁的意义不大,还容易因为递归调用自旋锁造成死锁。


相关文章推荐

Linux device drives chapter 2(构造和运行模块)

Linux device drives chapter 2 1.        如果你想编译驱动程序,那么你的系统必须存在构造好的内核源码树,否则驱动编译的时候头文件和链接文件找不到。 2. ...

Linux device drives chapter 4(调试技术)

第四章 内核调试技术 内核调试技术支持 make menuconfig对内核进行配置 在kernel hacking这一项中包含了一些内核的调试支持 make menuconfig之后就会看到...

Linux device drivers学习笔记(5)——uart primary driver code

#include #include #include #include #include #include #include #include #include #...

【原创】《Linux设备驱动程序》学习之循序渐进 --- 并发和竟态

【原创】《Linux设备驱动程序》学习之循序渐进 --- 并发和竟态

Linux设备驱动程序第三版学习(4)- 并发和竟态 .

第五章学习:并发和竟态 其实可以拿上“公共厕所”来做一个比喻,就是那种在大街上只有一个隔间的小型公厕。更容易理解并发、竟态和信号量。 把“临界区”理解为“公共厕所”(临界区:在任意给定的时刻,代码...

Linux Device Drivers学习笔记-Chapter.5

本章主要涉及并发管理,我觉得这部分的理解需要建立在大量实践的基础之上,光是像本科操作系统课上那样讲道理是很难体会的。我记录了一些关键的函数和数据结构。 1.Race Conditions(R...
  • kyokowl
  • kyokowl
  • 2011年04月01日 11:11
  • 529

Linux设备驱动程序第三版学习(4)- 并发和竟态

第五章学习:并发和竟态 其实可以拿上“公共厕所”来做一个比喻,就是那种在大街上只有一个隔间的小型公厕。更容易理解并发、竟态和信号量。 把“临界区”理解为“公共厕所”(临界区:在任意给定的时刻,代码...
  • Hens007
  • Hens007
  • 2012年02月16日 15:04
  • 487

linux设备驱动第五篇:驱动中的并发与竟态

目录[-] 综述 信号量与互斥锁 Completions 机制 自旋锁 其他的一些选择 不加锁算法 原子变量与位操作 seqlock(顺序锁) 读取-拷贝-更新(RCU) 小结 综述 在上...
  • yistn
  • yistn
  • 2015年04月11日 21:42
  • 212

LInux 的并发和竟态——中断、原子操作、自旋锁

并发是指的是多个执行单元同时被执行,而并发的执行单元对共享资源(硬件资源和软件上的全局变量、静态变量等)的访问很容易导致竟态。主要有以下三个方面: 一、对称处理器的多个CPU。 二、单CPU内,进...

Linux-MySleep函数实现与竟态条件

(一) 函数实现的整体框架 1>需要用到的函数接口 2>实现的整体过程思路 3>程序运行遇到可能情况的分析 4>优化结果与解决方案 (二)三个主要的函数接口 根据系统内部的sleep函数为基础,通...
  • cvhbfgh
  • cvhbfgh
  • 2017年08月05日 14:18
  • 71
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux device drives 5(并发与竟态)
举报原因:
原因补充:

(最多只允许输入30个字)