现在的位置: 首页 > 综合 > 正文

临界区的并发控制

2013年08月26日 ⁄ 综合 ⁄ 共 1726字 ⁄ 字号 评论关闭

一、并发与竞态
      并发指多个执行单元同时、并行被执行,而并发的执行单元对共享资源(全局变量,静态变量)的访问则容易导致竞态。
     几种情景:1、对称多处理器(SMP)的多个CPU
     2、单个CPU进程与抢占它的进程
 3、中断与进程之间
   访问共享资源区的代码区域称为临界区(critical sections).对临界区的保护方法:中断屏蔽,原子操作,自旋锁和信号量等途径。

二、中断屏蔽
    对单个CPU可采用的一种简单方法。
      local_irq_disable(); //关中断
      。。。。。
     critical sections //临界区
      。。。。。
     local_irq_enable();//开中断

三、原子操作

    Linux内核提供了一系列的函数来实现内核中的原子操作,分为针对位和整型变量进行原子操作,都依赖底层CPU的原子操作来实现。

四、自旋锁
   spin lock是一种对临界区进行互斥访问的典型手段。为获得一个自旋锁,在某CPU上运行的代码需先执行一个原子操作,该操作测试并设置某个内存变量,由于它是原子操作,所以在该操作完成之前其他执行单元无法访问该内存变量。如果测试结果表明锁已经空闲,程序则获得这个自旋锁并继续执行;否则,程序将在一个小的循环内重复这个‘测试并设置’的操作,即”自旋“。
    //定义一个自旋锁
   spinlock_t     lock;
   spin_lock_init(&lock); //初始化
  .....
   spin_lock(&lock);   //获取自旋锁
  .......//临界区
  spin_unlock(&lock);

  1、较长时间地占用锁,会降低系统的性能。
  2、自旋锁可能会导致系统死锁。常见情况为递归使用一个自旋锁。

读写自旋锁
      读写自旋锁是一种不自旋锁粒度更小的锁机制,只能有一个写进程,同时可以有几个读执行单元,但读写不能同时进行。
     基本操作有:定义和初始化读写自旋锁,读锁定,读解锁,写锁定,写解锁。
     在对共享资源进行读取之前,应该先进行读锁定,完成之后进行读解锁。
      在对共享资源进行写之前,应该先调用写锁定函数,完成之后调用写解锁函数。
    读写自旋锁一般使用:
rwlock_t   lock;
        relock_init(&lock); //定义初始化

//读
read_lock(&lock);
..... 
//临界资源
read_unlock(&lock);

//写
write_lock_irqsave(&lock);
....... //临界资源
write_unlock_irqrestore(&lock,flags);

五、信号量
semaphore是用于保护临界区的一种常用方法,与自旋锁类似。区别在于为获得信号量时,进程不会原地打转,而是进入休眠等待状态。
        semaphore相关的操作:
         //定义信号量
struct semaphore sem;

//初始化信号量
void sema_init(struct semaphore
*sem,int  val);

void init_MUTEX("struct semaphore  *sem");// 初始化一个用于互斥的信号量,sem设为1
void init_MUTEX_LOCKED(struct semaphore *sem);//初始化一个信号量,sem设为0

//获得信号量
void down(struct semaphore *sem);//会导致睡眠,不能在中断上下文使用
int  down_interruptible(struct  semaphore *sem);//因该函数进入睡眠状态的进程可被信号打断,信号也会导致该函数返回,这是返回值非0
int down_trylock(struct semaphore *sem);//如获得信号量,返回0;否则返回非0,不会导致调用者睡眠。

//释放信号量
void up(struct semaphore *sem);//释放信号量,唤醒等待者

信号量一般的使用方式:
DECLARE_MUTEX(sem);//定义互斥锁
down(&sem); //获得信号量,释放临界区
..... //临界区
up(&sem); //释放信号量

抱歉!评论已关闭.