Chinaunix首页 | 论坛 | 博客

  • 博客访问: 11961
  • 博文数量: 8
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 81
  • 用 户 组: 普通用户
  • 注册时间: 2015-04-09 22:57
个人简介

高中学历的渣渣

文章分类
文章存档

2015年(8)

我的朋友

分类: LINUX

2015-04-15 18:38:31


ARM Linux 源码分析系列文章基于 Linux 2.6.22 讲

解,转载请标明原处!


现代计算机一般都有多个处理器,这些处理器通常并发执行着某些程序,而这就会导致一些问题,比如说当多个处理器上的进程同时读写某些资源时(比如说变量),就有可能导致一些错误,而解决这个问题的最好方法就是使用一些同步机制来对处理器上的进程进行排队,那么,怎么排?很简单,我们可以只让第一个访问数据的处理器来处理数据,而后来的处理器则让他们执行一个几乎什么都不做的循环,等当前处理器处理完之后,再让下一个处理器进行处理即可。而实现这个同步机制的,就是我们这里要讲的自旋锁。

 

自旋锁是一种解决多处理器之间的并发问题而诞生的同步机制,他对单处理器的系统没有任何意义。他的原理很简单:给每个需要保护的资源上一把锁,每当有进程访问这个资源时都要先取得这个锁,如果顺利取到了就可以开始访问资源了,如果没取到,那就会进入一个不停检测锁是否被释放的循环等待锁被释放。

 

在 Linux 中使用 spinlock_t 结构体来描述一个自旋锁,其定义如下:




自旋锁的 raw_lock 成员是一个 raw_spinlock_t 结构体变量,他只有 个 lock 成员,这个 lock 成员就是这个自旋锁的锁值。当他为 时,就说明这个自旋锁是空闲的,我们取得锁后就可以访问资源了;当他为 时,则说明这个自旋锁已经被其他进程获得了,那么我们必须循环等待这个自旋锁被释放(这个循环就是所谓的自旋)。

 

自旋锁的操作

 

我们可以通过 DEFINE_SPINLOCK 来静态定义一个自旋锁,也可以通过其他内存分配函数分配一个自选锁然后通过 spinlock_init() 函数来初始化他,刚初始化的自旋锁都是空闲的自旋锁。

我们可以调用 spin_lock 宏来得到一个自旋锁。




spin_lock 宏的 lock参数就是需要得到的那个自旋锁的指针。宏会被转换成对 _spin_lock() 函数的调用。





在获得自旋锁后不允许在释放自旋锁前切换进程,否则一旦有另外一个进程也来获得这个自旋锁,那么就有可能形成死锁。为什么会形成死锁?这是因为内核态的时钟中断是不会执行调度的(除非发生抢占),所以另一个取锁的进程会不停的自旋而不会被调度出去,而调度不出去就意味着锁的拥有者无法得到 CPU 控制权去释放锁,这也就形成死锁了。作为开发者,当然可以确保在获得自旋锁后不主动调用 schedule(),但是因抢占而产生的调度是我们无法预测的,所以为了防止获得自旋锁后发生抢占,在 181 行会先禁止抢占。

182 行会进行一些调试工作(一般未配置,可看做空函数),然后在 183 行使用 _raw_spin_lock 宏来执行真正的取锁操作。




_raw_spin_lock 宏把自旋锁的锁值字段的指针传递给 __raw_spin_lock() 并由他来执行最后的操作。




33 行把lock->lock(自旋锁值)排他性地读入tmp
34 行检查锁值是否为 0,即自选锁是否是空闲的,如果自旋锁不是空闲的(锁值为1),那么 40 行和 41 行的代码就不会执行,而是直接在 42 行跳回到 33 行重新读取自旋锁值并重新进行判断。当然,如果自旋锁一直不被释放,那么当前进程就会这么一直循环下去,这也就是所谓的自旋。
40 行使用 strexeq 命令把 排他性地写入 lock->lock(取锁),并把写操作的结果保存到 tmp
41 行查看 tmp 的值是否为 0,如果为 就说明在 40 行取锁成功,否则就是 strexeq 在执行过程中和其他处理器核产生了冲突导致取锁失败,那么他会在 42 行跳回到 33 行重新取锁。
最后在 47 行设置一个内存屏障。


和 spin_lock 相对的,我们可以使用 spin_unlock 宏来释放一个自旋锁。



spin_unlock 宏的 lock 参数是被释放的自旋锁的指针。



_spin_unlock() 先调用 _raw_spin_unlock() 释放锁,然后在 330 行使能被 spin_lock 禁止的抢占。



最后 _raw_spin_unlock() 会被替换成__raw_spin_unlock() 来执行真正的释放操作。



释放一个自旋锁非常简单,因为他不需要像取锁那样要先判断锁是否为一把空闲锁,而是直接把他的锁值设为 即可(73行),做其他任何操作都会让解锁的效率变低。

阅读(347) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~