Linux设备驱动程序 之 自旋锁
概念
自旋锁可以再不能休眠的代码中使用,比如中断处理例程;在正确使用的情况下,自旋锁通常可以提供比信号量更高的性能;
一个自旋锁是一个互斥设备,它只能由两个值,锁定和解锁;通常实现为某个整数值中的单个位;希望获得特定锁的代码测试相关位,如果锁可用,则锁定位被设置,而嗲吗继续进入临界区;相反,如果锁被其他人获得,则代码进入忙循环并重复检查这个锁,直到该锁可用为止;这循环就是自旋锁自旋的部分;
自旋锁在不同的架构上实现有所不同,但是核心概念低于所有系统都都是一样的,当存在某个自旋锁时,等待执行忙循环的处理器做不了任何有用的工作;
自旋锁最初是为了在多处理器系统上使用而设计的,考虑到并发问题,单处理器工作站在运行可抢占内核时,其行为类似于SMP;因为抢占,即使不打算在SMP系统上运行自己的嗲吗,我们仍然需要实现正确的锁定;
自旋锁和原子上下文
适用于自旋锁的规则是:任何拥有自旋锁的代码都必须是原子的,它不能休眠;事实上,它不能因为任何原因放弃处理器,除了服务中断以外(某些情况下此时也不能放弃处理器);
内核抢占的情况有自旋锁代码本身处理;任何时候,只要内核代码拥有自旋锁,在相关处理器上的抢占就会被禁止;甚至在单处理器上,也必须以同样的方式禁止抢占以避免竞态;
在拥有锁的时候避免休眠有时候很难做到,休眠可能发生在很多无法预期的地方,当我们编写需要在自旋锁下执行的代码时,必须注意每一个调用的函数;
另外一种情形,当驱动程序正在执行时,并且获取了一个锁,这个锁控制着对设备的访问;在这个时候,设备产生了一个中断,导致中断处理例程会被调用;而中断处理例程在访问设备之前,也要获取这个锁;在中断处理例程中拥有锁是合法的;但是,中断处理例程在最初拥有锁的代码所在的处理器上运行时,处于自旋获取锁的状态,而此时非中断代码将没有任何机会释放这个锁;处理器将永远自旋下去;为了避免这种情况,我们需要在拥有自旋锁时禁止本地cpu对的中断;
自旋锁使用的最后一个重要规则:自旋锁必须在可能的最短时间内拥有;拥有自旋锁的时间越长,其他处理器不得不自旋等待释放该自旋锁的时间就越长;长时间拥有锁将阻止当前处理器的调度,这意味着更高优先级的进程不得不等待;为了避免这种问题,谨记拥有锁的时间越短越好;
自旋锁使用
使用自旋锁需要包含<linux/spinlock.h>头文件;实际锁具有spinlock_t类型,和其他任何数据结构类似,一个自旋锁必须被初始化;
编译期间静态的声明和初始化使用如下方式:
#define DEFINE_SPINLOCK(x)
或者可以调用下面宏对spinlock进行运行时的动态初始化:
#define spin_lock_init(_lock)
在进入临界区之前,需要使用spin_lock相关函数获取锁:注意:所有的自旋锁等待在本质上都是不可中断的,一旦调用了spin_lock,在获得锁之前将一直处于自旋状态;
static __always_inline void spin_lock(spinlock_t *lock) /* 禁止软中断,硬件中断是打开的 */
static __always_inline void spin_lock_bh(spinlock_t *lock) /* 禁止本地中断,不保存中断状态,需要确保没有其他代码禁止本地处理器中断 */
static __always_inline void spin_lock_irq(spinlock_t *lock) /* 禁止本地处理器中断,保存中断状态 */
#define spin_lock_irqsave(lock, flags)
在离开临界区时,要释放已经获取的锁,可以使用下面方法:
static __always_inline void spin_unlock(spinlock_t *lock) static __always_inline void spin_unlock_bh(spinlock_t *lock) static __always_inline void spin_unlock_irq(spinlock_t *lock) static __always_inline void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
内核还提供了非阻塞的锁定方法:
static __always_inline int spin_trylock(spinlock_t *lock) static __always_inline int spin_trylock_bh(spinlock_t *lock) static __always_inline int spin_trylock_irq(spinlock_t *lock) #define spin_trylock_irqsave(lock, flags)
读写自旋锁
内核提供了自旋锁的读/写形式,这种锁允许任意数量的读取者同时进入临界区,但写入者必须互斥访问,即写者会自旋等待获取锁;读/写自旋锁使用rwlock_t类型,在<linux/rwlock_types.h>和<linux/rwlock.h>中定义,使用读写自旋锁需要包含这两个头文件;
静态声明和初始化:
#define DEFINE_RWLOCK(x)
动态声明和初始化:
# define rwlock_init(lock)
获取锁的方法如下:
#define read_trylock(lock)
#define write_trylock(lock) #define write_lock(lock)
#define read_lock(lock) #define read_lock_irqsave(lock, flags)
#define write_lock_irqsave(lock, flags) #define read_lock_irq(lock) _raw_read_lock_irq(lock)
#define read_lock_bh(lock) _raw_read_lock_bh(lock)
#define write_lock_irq(lock) _raw_write_lock_irq(lock)
#define write_lock_bh(lock) _raw_write_lock_bh(lock)
释放锁的方法如下:
#define read_unlock(lock)
#define write_unlock(lock)
#define read_unlock_irq(lock)
#define write_unlock_irq(lock)
#define read_unlock_irqrestore(lock, flags)
#define read_unlock_bh(lock)
#define write_unlock_irqrestore(lock, flags)
#define write_unlock_bh(lock)
Linux设备驱动程序 之 自旋锁的更多相关文章
- Linux设备驱动程序 之 顺序锁
当要保护的资源很小,很简单,会频繁的被访问而且写入访问很少的且必须快速时(即读不允许让写饥饿),就可以使用顺序锁(seqlock):从本质上讲,顺序锁会允许读取者对资源的自由访问,但需要读取者检查是否 ...
- linux设备驱动程序该添加哪些头文件以及驱动常用头文件介绍(转)
原文链接:http://blog.chinaunix.net/uid-22609852-id-3506475.html 驱动常用头文件介绍 #include <linux/***.h> 是 ...
- 【转】linux设备驱动程序中的阻塞机制
原文网址:http://www.cnblogs.com/geneil/archive/2011/12/04/2275272.html 阻塞与非阻塞是设备访问的两种方式.在写阻塞与非阻塞的驱动程序时,经 ...
- Linux内核同步:自旋锁
linux内核--自旋锁的理解 自旋锁:如果内核配置为SMP系统,自旋锁就按SMP系统上的要求来实现真正的自旋等待,但是对于UP系统,自旋锁仅做抢占和中断操作,没有实现真正的“自旋”.如果配置了CON ...
- Linux设备驱动程序 第三版 读书笔记(一)
Linux设备驱动程序 第三版 读书笔记(一) Bob Zhang 2017.08.25 编写基本的Hello World模块 #include <linux/init.h> #inclu ...
- Linux设备驱动程序学习之分配内存
内核为设备驱动提供了一个统一的内存管理接口,所以模块无需涉及分段和分页等问题. 我已经在第一个scull模块中使用了 kmalloc 和 kfree 来分配和释放内存空间. kmalloc 函数内幕 ...
- 教你写Linux设备驱动程序:一个简短的教程
教你写Linux设备驱动程序:一个简短的教程 http://blog.chinaunix.net/uid-20799298-id-99675.html
- linux设备驱动程序_hello word 模块编译各种问题集锦
在看楼经典书籍<linux设备驱动程序>后,第一个程序就是编写一个hello word 模块. 原以为非常easy,真正弄起来,发现问题不少啊.前两天编过一次,因为没有记录,今天看的时候又 ...
- Linux设备驱动程序学习----1.设备驱动程序简介
设备驱动程序简介 更多内容请参考Linux设备驱动程序学习----目录 1. 简介 Linux系统的优点是,系统内部实现细节对所有人都是公开的.Linux内核由大量复杂的代码组成,设备驱动程序可以 ...
随机推荐
- LeetCode:197.上升的温度
题目链接:https://leetcode-cn.com/problems/rising-temperature/ 题目 给定一个 Weather 表,编写一个 SQL 查询,来查找与之前(昨天的)日 ...
- 关于一些JS的运算符
首先呢,什么是JavaScript:JavaScript是一种脚本语言,也是一种解释型语言,更是一种由数据值决定变量类型的弱类型语言 JavaScript主要由三部分组成 ECMAScript 这个 ...
- android默认获取敏感权限
1.通过系统签名获取权限 定制系统中,可以通过源码的签名文件对应用进行签名,在应用的AndroidManifest.xml中配置好参数,如图 <manifest xmlns:android=&q ...
- ABAP下载的病毒扫描Virus Scan
当我使用CL_HTTP_ENTITY=>IF_HTTP_ENTITY~GET_DATA从网络下载数据时,遇到异常CX_VSI: 错误原因是数据从网络下载到Netweaver服务器上之后,在服务器 ...
- world 页面横向
今天浏览world时,发现一个现象: 出现的页面比较宽,如何做的呢? 操作如下: 1.打开一个新的world 2.选择布局页签,分隔符,分节符的下一页 3.鼠标放到第二页上,选择页签布局,纸张方向,选 ...
- ulimit 命令详解 socket查看linux最大文件打开数
ulimit 命令详解 Linux对于每个用户,系统限制其最大进程数.为提高性能,可以根据设备资源情况,设置各linux 用户的最大进程数 可以用ulimit -a 来显示当前的各种用户进程限 ...
- django-bootstrap4|django 加载popper.min.js失败
1.现象 2.解决过程 2.1.右键查看网页源代码 在浏览器地址栏打开popper.min.js对应的URL,发现无法打开,这个地址是国外的,需要找一个可访问的地址替换. 2.2.找到URL在djan ...
- web开发:定位布局
一.盒子的显隐 二.小米topbar 三.相对定位 四.决定定位 五.固定定位 六.z-index属性 七.流式布局思想 八.hover父子悬浮 一.盒子的显隐 1.同一结构下, 如果采用浮动布局,所 ...
- ServiceLoader在SPI中的重要作用分析
对于线程上下文类加载器在之前已经对它进行了详细的理论化的学习,其中对于这个类加载器应用最多的也就是在SPI场合下用来打破双亲委托机制,如之前所描述的: 这次举一个具体的例子来进一步的加深对线程上下文类 ...
- python_连接MySQL数据库(未完)
1.增 # 导入库 import pymysql # 创建连接 conn = pymysql.connect(host='localhost',user='root',password='fuqian ...