linux内核中访问共享资源

访问共享资源的代码区域称为临界区,临时以某种互斥机制加以保护。中断屏蔽、原子操作
自旋锁和信号量是Linux设备驱动中可采用的互斥途径。

在单CPU范围内避免竞态的一种简单方法是在进入临界区之前屏蔽系统的中断。
CPU一般都具备屏蔽中断和打开中断的功能。

中断屏蔽的使用方法:
Local_irq_disable();  //屏蔽中断--->和它不同的是local_irq_save除了禁止中断操作以外还可以保存目前CPU的中断位信息

......
临界区
......

Local_irq_enable();   //开中断--->local_irq_restore进行的是与local_irq_save相反的操作。

要求:在屏蔽了中断之后,当前的内核执行路径应当尽快地执行完临界区的代码。
如果只是想禁止中断的底半部,应当使用local_bh_disable(),使能local_bh_disable()
禁止的底半部应该调用local_bh_enable();

原子操作:指的是在执行过程中不会被别的代码路径所中断的操作
内核中有一些函数分为两类,分别针对位和整型变量进行原子操作。共同点:在任何情况下操作都是原子的,内核代码可以安全地调用
它们而不被打断。都是依赖底层CPU的原子操作来实现的。所以这些函数都与CPU的架构密切相关。

SMP:多处理器结构的简称.
自旋锁的作用:
    自旋锁spin_lock是一种对临界资源进行互斥访问的典型手段,这个名字是由于它的工作方式。
要获得自旋锁,在CPU上运行的代码需要先执行一个原子操作,该操作测试并设置某个内存变量,
由于它是原子操作,所以在操作完成之前其它执行单元不可能访问这个内存变量。
    如果测试结果表明锁已经空闲,则程序获得这个自旋锁并继续执行;如果测试结果表明锁
仍被占用,程序将在一个小循环内重复这个"测试并设置"操作,即进行所谓的“自旋”,通俗的说
就是在原地打转,当自旋锁的持有者通过重新设置该变量释放这个自旋锁后,某个等待的"测试并设置"的操作
向其调用者报告锁已经被释放。
    自旋锁操作主要针对SMP或单CPU但内核可抢占的情况,对于单CPU和内核不支持抢占的系统,自旋锁退化为空操作。
在单CPU和内核可抢占的系统中,自旋锁持有期间内核的抢占将被禁止。由于内核抢占的单CPU兄的行为实际
很类似于SMP系统,隐私在这样的单CPU系统中使用自旋锁就十分必要。

Linux系统中与自旋锁相关的操作主要有以下4种:
定义一个自旋锁:
Spinlock_t  spin ;
初始化自旋锁:
Spin_lock_init(lock) ;
获得自旋锁:
Spin_lock(lock);
如果能立即获得锁,就马上返回,否则,它将自旋,直到该自旋锁的保持者释放。
Spin_trylock(lock);
尝试获得自旋锁lock,如果可以立即获得,获得并返回真,否则立即返回假,实际上不再原地打转.
释放锁:
Spin_unlock(lock);
与spin_trylock或spin_lock配对使用。
一般这样使用:
Spinlock_t lock ;
Spin_lock_init(&lock);
Spin_lock(&lock);//获取自旋锁,包含临界区
.....//临界区
Spin_unlock(&lock); //解锁

   使用自旋锁实际上是忙等锁,当锁不可用时,CPU一直循环执行测试并设置该锁直到可用而
取得该锁。此时CPU在等待自旋锁不做任何有用的工作,仅仅是等待。因此只有在
占用锁极短的情况下,使用自旋锁才是合理的,如果临界区有很大或者有共享设备的时候
,需要较长时间占用锁,会降低系统的性能。
自旋锁可能导致系统死锁,常见情况就是递归一个自旋锁,如果已经拥有某个自旋锁的
CPU想第二次获得这个自旋锁,则该CPU将死锁。如果进程获得自旋锁后再阻塞,也可能
导致死锁的发生。copy_from_user(),copy_to_user()和kmalloc()等函数都有可能引起阻塞。
因此自旋锁的占用期间不能调用这些函数。

读写自旋锁:是一种比自旋锁粒度更小的锁机制,它保留了自旋的概念,但是在写操作方面,
只能最多有一个写进程,在读操作方面,同事可以有多个读执行单元。当然,读和写也不能同事进行。
定义和初始化:
rwlock_t lock = RW_LOCK_LOCKED ; //静态初始化
rwloct_t lock ; 
rwlock_init(&lock);
读锁定:
read_lock(rwlock_t *lock);
read_lock_irq(rwlock_t *lock);
read_lock_irqsave(rwlock_t *lock , unsigned long flags);
read_lock_bh(rwlock_t *lock);
读解锁:
read_unlock(rwlock_t *lock);
read_unlock_irq(rwlock_t *lock);
read_unlock_irqrestore(rwlock_t *lock , unsigned long flags);
read_unlock_bh(rwlock_t *lock);

......

时间: 2024-08-30 06:57:18

linux内核中访问共享资源的相关文章

大话Linux内核中锁机制之RCU、大内核锁

大话Linux内核中锁机制之RCU.大内核锁 在上篇博文中笔者分析了关于完成量和互斥量的使用以及一些经典的问题,下面笔者将在本篇博文中重点分析有关RCU机制的相关内容以及介绍目前已被淘汰出内核的大内核锁(BKL).文章的最后对<大话Linux内核中锁机制>系列博文进行了总结,并提出关于目前Linux内核中提供的锁机制的一些基本使用观点. 十.RCU机制 本节将讨论另一种重要锁机制:RCU锁机制.首先我们从概念上理解下什么叫RCU,其中读(Read):读者不需要获得任何锁就可访问RCU保护的临界

大话Linux内核中锁机制之信号量、读写信号量

大话Linux内核中锁机制之信号量.读写信号量 在上一篇博文中笔者分析了关于内存屏障.读写自旋锁以及顺序锁的相关内容,本篇博文将着重讨论有关信号量.读写信号量的内容.  六.信号量 关于信号量的内容,实际上它是与自旋锁类似的概念,只有得到信号量的进程才能执行临界区的代码:不同的是获取不到信号量时,进程不会原地打转而是进入休眠等待状态.它的定义是include\linux\semaphore.h文件中,结构体如图6.1所示.其中的count变量是计数作用,通过使用lock变量实现对count变量的

大话Linux内核中锁机制之原子操作、自旋锁【转】

转自:http://blog.sina.com.cn/s/blog_6d7fa49b01014q7p.html 多人会问这样的问题,Linux内核中提供了各式各样的同步锁机制到底有何作用?追根到底其实是由于操作系统中存在多进程对共享资源的并发访问,从而引起了进程间的竞态.这其中包括了我们所熟知的SMP系统,多核间的相互竞争资源,单CPU之间的相互竞争,中断和进程间的相互抢占等诸多问题. 通常情况下,如图1所示,对于一段程序,我们的理想是总是美好的,希望它能够这样执行:进程1先对临界区完成操作,然

Linux内核中的jiffies及其作用介绍及jiffies等相关函数详解

在LINUX的时钟中断中涉及至二个全局变量一个是xtime,它是timeval数据结构变量,另一个则是jiffies,首先看timeval结构struct timeval{time_t tv_sec; /***second***/susecond_t tv_usec;/***microsecond***/}到底microsecond是毫秒还是微秒?? 1秒=1000毫秒(3个零),1秒=1000 000微秒(6个零),1秒=1000 000 000纳秒(9个零),1秒=1000 000 000

大话Linux内核中锁机制之原子操作、自旋锁

转至:http://blog.sina.com.cn/s/blog_6d7fa49b01014q7p.html 很多人会问这样的问题,Linux内核中提供了各式各样的同步锁机制到底有何作用?追根到底其实是由于操作系统中存在多进程对共享资源的并发访问,从而引起了进程间的竞态.这其中包括了我们所熟知的SMP系统,多核间的相互竞争资源,单CPU之间的相互竞争,中断和进程间的相互抢占等诸多问题. 通常情况下,如图1所示,对于一段程序,我们的理想是总是美好的,希望它能够这样执行:进程1先对临界区完成操作,

大话Linux内核中锁机制之内存屏障、读写自旋锁及顺序锁

大话Linux内核中锁机制之内存屏障.读写自旋锁及顺序锁     在上一篇博文中笔者讨论了关于原子操作和自旋锁的相关内容,本篇博文将继续锁机制的讨论,包括内存屏障.读写自旋锁以及顺序锁的相关内容.下面首先讨论内存屏障的相关内容. 三.内存屏障 不知读者是是否记得在笔者讨论自旋锁的禁止或使能的时候,提到过一个内存屏障函数.OK,接下来,笔者将讨论内存屏障的具体细节内容.我们首先来看下它的概念,Memory Barrier是指编译器和处理器对代码进行优化(对读写指令进行重新排序)后,导致对内存的写入

大话Linux内核中锁机制之完成量、互斥量

大话Linux内核中锁机制之完成量.互斥量 在上一篇博文中笔者分析了关于信号量.读写信号量的使用及源码实现,接下来本篇博文将讨论有关完成量和互斥量的使用和一些经典问题.  八.完成量 下面讨论完成量的内容,首先需明确完成量表示为一个执行单元需要等待另一个执行单元完成某事后方可执行,它是一种轻量级机制.事实上,它即是为了完成进程间的同步而设计的,故而仅仅提供了代替同步信号量的一种解决方法,初值被初始化为0.它在include\linux\completion.h定义. 如图8.1所示,对于执行单元

基本数据结构和算法在Linux内核中使用

基本数据结构和算法在Linux内核中使用 gaufunga day ago 搬运工 Linux内核(源代码的链接在github). 1.链表.双向链表.无锁链表. 2.B+ 树,这是一些你无法在教科书上找到的说明. 一个相对简单的B+树的实现.我把它作为一个学习练习来帮助理解B+树是如何工作的.这同样也被证明是有用的. ... 一个在教科书中并不常见的技巧.最小的值在右侧而不是在左侧.所有在一个节点里用到的槽都在左侧,所有没有用到的槽包含了空值(NUL).大多数操作只简单地遍历所有的槽一次并在第

Linux内核中双向链表的经典实现

概要 前面一章"介绍双向链表并给出了C/C++/Java三种实现",本章继续对双向链表进行探讨,介绍的内容是Linux内核中双向链表的经典实现和用法.其中,也会涉及到Linux内核中非常常用的两个经典宏定义offsetof和container_of.内容包括: 1. Linux中的两个经典宏定义 2. Linux中双向链表的经典实现 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3562146.html 更多内容: 数据结构与算法系列 目录