事实上这blog都是阅读ldd3时的一些总结,巩固自己的学习。也方便后期的使用。大家也能够直接阅读ldd3原文。

锁陷阱

        所谓的锁陷阱就是防止死锁。
        不明白的规则:
        1、不论是信号量还是 自旋锁,都不同意锁拥有者第二次获得这个锁(会死锁)。
        2、系统直接调用的那些函数要获得信号量,保护要訪问的设备结构。而内部函数的訪问则能够依据须要上锁。

        锁顺序规则:
        1、假设都要获取一系列锁的话,那么能够依照一定顺序规则来获取锁,即:获取多个锁时,锁的顺序一直。
        2、假设要获取自己的局部锁和系统的中心锁,则先获取自己的局部锁,然后再去获取中心锁;
        3、假设要获取信号量和自旋锁,则须要先获取信号量,由于释放信号量的函数down有可能会休眠。

        免锁算法:
        有非常多的免锁算法,ldd3中提到一种循环缓存区,感觉非常实用(工作中也遇到过)。
        循环缓冲区:就是比方一个数组A[9]为临界区。能够从A[0]端往A[9]端方向读取数据,从A[9]端往A[0]端写入数据。

就是一个互相追逐的算法,这样能够不用锁就能保证数据的一致性;

        工作中也遇到过这样的缓冲区,把请求结构体往一个循环队列中放。而内核在队列的另外一端读取请求结构体去运行。

原子操作

        原子操作在内核源码中使用很频繁,事实上这个原子操作主要是对变量操作的。在本质上来说这也是一种锁。由于假设我们用一种锁机制去锁住一个变量,这样就有点浪费了。毕竟锁还是要耗费cpu的一些时间的,为了一个小小的变量,动用锁,不值当。

所以原子操作就应运而生了。

        头文件 <asm/atomic.h>,数据结构为:atomic_t

        void  atomic_set(atomic_t  *v,  int  i); // 动态初始化,就是原子赋值:v = i
        atomic_t  v  = ATOMIC_INIT(o);// 静态初始化,在编译时初始化

        int  atomic_read(atomic_t  *v);// 返回V的当前值

        void  atomic_add(int i,  atomic_t  *v);// 将i 加到V指向的原子变量上,返回为void,是由于大多数情况下不须要这个返回值,所以不返回,减少函数成本;
        void  atomic_sub(in  i,  atomic_t  *v);// 和上面函数功能相反

        void  atomic_inc(atomic_t  *v);// 自增
        void  atomic_dec(atomic_t  *v);// 自减

       int  atomic_inc_and_test(atomic_t  *v);
       int  atomic_dec_and_test(atomic_t  *v);
       int  atomic_sub_and_test(int i ,  atomic_t  *v);
       运行操作并測试结果:假设操作后,原子值为0。则返回true;否则返回false;

       int atomic_add_negative(int  i,  atomic_t  *v);// 将i加到v上,假设结果为负数。返回true。否则为false;

        int  atomic_add_return(int i,  atomic_t  *v);       
        int  atomic_sub_return(int i,  atomic_t  *v);       
        int  atomic_inc_return(atomic_t  *v);       
        int  atomic_dec_return(atomic_t  *v);       
        运行上面相应的操作,然后返回操作后的新值V

位操作

        和原子操作类似,位操作其本质也算是一种锁机制。仅仅是相对来说粒度会小些。

信号量和自旋锁是对一段代码,一块内存等进行保护的;原子操作是对变量进行保护的;而位操作是对变量中的各个位进行设置的,当然这也是原子操作。

由于原子操作很快,能够用单个机器指令来运行,所以不用禁止中断。

        nr參数一般被定义为int,但也有些不同的系统定位为unsigned long等;        

        void  set_bit(nr,  void *addr);// 设置addr指向的数据项的第nr位
        void  clear_bit(nr,  void *addr);//清楚addr指向的数据项的第nr位

        void  change_bit(nr,  void *addr);// 切换指定位

        test_bit(nr,  void *addr);//返回当前值

int   test_and_set_bit(nr,  void *addr);

        int   test_and_clear_bit(nr,  void *addr);
        int   test_and_change_bit(nr,  void *addr);
        运行相应的操作,而且返回  先前  的值

seqlock

        seqlock可对共享资源的高速、免锁訪问。当要保护的资源非常小、非常easy、会频繁被訪问并且写入訪问非常少发生且必须高速时,就能够使用seqlock。seqlock同意读取者自由訪问。但要检查是否和写入者发生冲突,当发生冲突时,要又一次读取数据。seqlock不保护含有指针的数据结构。由于在写入 者改动该数据的时候,读取者可能会读取一个无效的指针;
        头文件 <linux/seqlock.h> 
        初始化:
        seqlock_t   lock1 = SEQLOCK_UNLOCKED;//静态初始化
        seqlock_t   lock2;
        seqlock_init(&lock2);// 动态初始化

        读取者在訪问临界区时。先获取一个无符号整数,然后完毕自己的操作,退出时再获取下该整数。对照下看是否相等;假设不相等,则须要又一次获取个整数==》完毕操作==》退出获取參数比較;代码例如以下:
        unsigned  int seq;
        do {
               seq = read_seqbegin(&the_lock);
               /* 完毕对应的工作 */
        }while (read_seqretry(&the_lock,  seq));
        这类锁仅仅是用来保护简单的计算,可是须要数据一致性,所以不一致就必须又一次读取数据;

        假设在中断处理例程中使用seqlock,则应该使用IRQ安全的版本号:
        unsigned int read_seqbegin_irqsave(seqlock_t *lock, unsigned  long flags);
        int read_seqretry_irqrestore(seqlock_t *lock,unsigned int seq,  unsigned  long flags);

        写入者进入由seqlock保护的临界区时必须获得一个相互排斥量:
        void  write_seqlock(seqlock_t  *lock);
        void  write_sequnlock(seqlock_t  *lock);

        因为写入锁使用自旋锁实现,自旋锁控制写入訪问,所以自旋锁的常见变种都能够使用:
        void  write_seqlock_irqsave(seqlock_t  *lock, unsigned long  flags); 
        void  write_seqlock_irq(seqlock_t  *lock);
        void  write_seqlock_bh(seqlock_t  *lock);

        void  write_sequnlock_irqrestore(seqlock_t  *lock, unsigned long  flags);
        void  write_sequnlock_irq(seqlock_t  *lock,);
        void  write_sequnlock_bh(seqlock_t  *lock);



linux设备驱动程序之并发和竞态(二)的更多相关文章

  1. Linux内核中的并发与竞态概述

    1.前言 众所周知,Linux系统是一个多任务的操作系统,当多个任务同时访问同一片内存区域的时候,这些任务可能会相互覆盖内存中数据,从而造成内存中的数据混乱,问题严重的话,还可能会导致系统崩溃. 2. ...

  2. Linux设备驱动程序 之 并发及其管理

    竞态产生 Linux系统找那个存在大量的并发联系,因此会导致可能的竞态: 1. 正在运行的用户空间进程可以以多种组合方式访问我们的代码: 2. SMP系统甚至可以再不同的处理器上同时执行我们的代码: ...

  3. Linux驱动开发4——并发和竞态

    Linux系统处于一个高并发的运行环境,不管是系统调用还是中断都要求可重入,但是有一些系统资源处于临界区,因此,必须保证临界区资源访问的原子性. 对于临界区资源被占用时,发起访问的进程,有三种处理方法 ...

  4. 《Linux 设备驱动程序》读后感。 并发,竞态,死锁。

    1. 概念 并发:在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行. 来源: 1. Linux ...

  5. 漫画|Linux 并发、竞态、互斥锁、自旋锁、信号量都是什么鬼?(转)

    知乎链接:https://zhuanlan.zhihu.com/p/57354304 1. 锁的由来? 学习linux的时候,肯定会遇到各种和锁相关的知识,有时候自己学好了一点,感觉半桶水的自己已经可 ...

  6. Linux内核分析(七)----并发与竞态

    原文:Linux内核分析(七)----并发与竞态 Linux内核分析(七) 这两天家里的事好多,我们今天继续接着上一次的内容学习,上次我们完善了字符设备控制方法,并深入分析了系统调用的实质,今天我们主 ...

  7. linux设备驱动程序第四部分:从如何定位oops对代码的调试方法,驱动线

    在一个我们谈到了如何编写一个简单的字符设备驱动程序,我们不是神,编写肯定会失败的代码,在这个过程中,我们需要继续写代码调试.在普通c应用.我们经常使用printf输出信息.或者使用gdb要调试程序,然 ...

  8. Linux设备驱动程序学习----2.内核模块与应用程序的对比

    内核模块与应用程序的对比 更多内容请参考Linux设备驱动程序学习----目录 1. 内核模块与应用程序的对比 内核模块和应用程序之间的不同之处: 大多数中小规模的应用程序是从头到尾执行单个任务,而模 ...

  9. LDD3之并发和竞态-completion(完毕量)的学习和验证

    LDD3之并发和竞态-completion(完毕量)的学习和验证 首先说下測试环境: Linux2.6.32.2 Mini2440开发板 一開始难以理解书上的书面语言,这里<linux中同步样例 ...

随机推荐

  1. LAMP第二部分apache的配置

    1. 下载discuz! mkdir /data/wwwcd /data/wwwmv /root/Discuz_X3.2_SC_GBK.zip .wget http://download.comsen ...

  2. proteus仿真 引脚显示电平变化但不能显示波形

    proteus仿真 引脚显示电平变化但不能显示波形 原来是没有选择通道问题,proteus默认优先使用A通道才会显示波形,如果优先使用B,C,D通道,需要选择...

  3. [TC_SRM_460]TheCitiesAndRoadsDivOne

    [TC_SRM_460]TheCitiesAndRoadsDivOne 试题描述 John and Brus have become very famous people all over the w ...

  4. [luoguP2657] [SCOI2009]windy数(数位DP)

    传送门 f[i][j]表示位数为i,第i位为j的windy数的个数 先预处理出f数组. 求的时候先算没有前导0的答案,再算位数和给定的数相同的答案. #include <cmath> #i ...

  5. 秀秀的照片(photo)

    秀秀的照片(photo) 题目描述 华华在和秀秀视频时有截很多图.华华发现秀秀的每一张照片都很萌很可爱.为什么会这样呢?华华在仔细看过秀秀的所有照片后,发现秀秀的照片都具有一个相同的性质. 设秀秀的分 ...

  6. 数组去重js方式

    var selectmap = new Array(); /(\x0f[^\x0f]+)\x0f[\s\S]*\1/.test("\x0f"+selectmap.join(&quo ...

  7. 模板jinja2常用方法

    http://docs.jinkan.org/docs/jinja2/ 摘自 http://www.pythontip.com/blog/post/5455/ 数学运算       +, -, *,  ...

  8. Windows + Eclipse 构建mahout运行环境

    mahout的完整运行还是需要hadoop的支持的,不过很多算法只需要能把hadoop的jar包加入到classpath之中就能正常运行. 比如我们在使用LogisticModelParameters ...

  9. (一) Spring基础概述

    1.历史 第一阶段:xml配置 在Spring1.x时代,使用Spring开发满眼都是xml配置的Bean,随着项目的扩大,我们需要把xml配置文件分布放到不同配置文件中,需要频繁的在开发的类和配置文 ...

  10. 《Linux内核Makefile分析》之 auto.conf, auto.conf.cmd, autoconf.h【转】

    转自:http://blog.sina.com.cn/s/blog_87c063060101l25y.html 转载:http://blog.csdn.net/lcw_202/article/deta ...