转自:http://blog.chinaunix.net/uid-24943863-id-3193530.html

并发导致竟态,从而导致对共享数据的非控制访问,产生非预期结果,我们要避免竟态的发生。遵循以下原则:1,尽量避免资源共享;2,显示地管理对共享资源的访问。管理技术通常为“锁定”或者“互斥”,保证任何时刻只有一个执行线程可操作共享资源。

        几个重要的概念:1,原子操作,顾名思义,就是说该操作是原子性的(原子是保持物质物理新性质的最小单位),不可分割的,亦即操作要么处于不间断地执行的状态,要么处于不执行的状态。2,临界区,临界区是这么一段代码,这段代码在任意给定时刻只能被一个线程执行。3,休眠,休眠是程序处于阻塞的状态,进程到达某个时间点,此时它不能进行任何处理(可能是等待某资源),它让出处理器给别的进程用,直到它能够完成自己的处理为止。相当于进程进入睡觉的状态,但它永远不知道要睡多长时间,也许它几天后才醒来,但是它会认为只是打了个盹。
         信号量的本质是一个整数值,可以取0或者正整数,信号量为0表示该信号量标志的资源对当前进程不可用(可能其他线程正在使用),为正整数n表示允许唤醒n个线程对资源进行操作。信号量配合一对函数P和V使用,P是Proberen(荷兰语),测试的意思,V(Verhogen)是增加。P操作对应down()函数,测试信号量的值,若大于0,则信号量值减1,进程继续;若信号量等于0,那么调用进程休眠(调用sleep()),此时down()并没有结束(而是处于休眠状态)。P操作是原子操作,也就是说检查信号量和修改信号量(或者休眠,如果信号量为0的话)是一个单一的不可分割的操作。V操作对应于up()函数,完成对信号量的加1操作,如果有线程在等待该信号量而处于休眠状态(调用down()检查到信号量为0),则由系统唤醒其中一个线程完成down()函数。虽然此刻信号量又回到了0,但是处于等待的进程数少了一个,等该进程完成了对共享资源的访问,需要调用up()函数释放信号量,使得其他等待该信号量的线程能够继续。
    要使用信号量,首先需要初始化,使用下面的函数进行初始化一个信号量,val用来指定信号量的初始值,即有最多有val 个进程可以并发访问down()和up()之间保护的资源。    
  void sema_init(struct semaphore *sem,int val)
内核中P操作有三个版本
void down(struct semaphore *sem)
int down_interruptible(struct semaphore *sem)
int down-trylock(struct semaphore *sem) //检查信号量后立即返回,不进入休眠
down_interruptible()是dwon()的可中断版本,也就是说用户可以中断正在等待该信号量的进程。这个函数是我们需要始终使用的版本。
down()和up()是成对调用的,up()函数用于释放信号量,其函数原型是
void up(struct semaphore *sem)
        当调用sema_init()函数初始化信号量,如果val取1,那么该信号量就是一个互斥量!互斥量是只有两个状态的变量,解锁(0)和加锁(非零)。也就是说信号量可以实现互斥,但并不是所有互斥量都是信号量。信号量和互斥量就像有交集的两个集合。对于一些不能休眠的代码,如中断处理handle,不能使用信号量的down()函数,因为down会导致休眠,这时候可以使用自旋锁来实现互斥!自旋锁的工作原理与信号量颇为相似,spin_lock()不断检查锁是否可用,当锁可用时(处于解锁状态,互斥量为0),那么加锁(互斥量设置为非零),进程可以继续,进入临界区执行代码,当锁不可用时,那么spin_lock()进入忙循环并重复检查锁,直到锁可用,代码此刻在这里循环,像不像自旋(down()函数此时则进入休眠)。与信号量一样,使用自旋锁时必须对互斥量进行初始化,有两种方法可以完成初始化,一是声明锁时赋值,二是调用初始化函数传递实参
spinlock_t mylock=SPIN_LOCK_UNLOCKED
void spin_lock_init(spinlock_t *lock)
获得锁的函数(相当于信号量中的P操作)是
void spin_lock(spinlock_t *lock)
同样,用完之后需要释放锁,调用下面的代码
void spin_unlock(spinlock_t *lock)
        由于自旋锁会造成死锁,因此需要小心使用。需要遵循以下规则:
1,任何拥有自旋锁的代码必须是原子的,它不能休眠!注意,copy_from_user,kmalloc等会导致休眠的函数在拥有spinlock的临界区是不能使用的。
2,在拥有自旋锁时禁止中断,使用函数spin_lock_irqsave()或spin_lock_irq()代替spin_lock()
3,自旋锁必须在可能的最短时间内拥有。也就是锁自旋锁保护的临界区代码执行得越快越好。
4,必须避免获得锁的函数调用同样试图获得该锁的函数,否则会造成死锁。
5,在必须获得多个锁时,应该始终以相同的顺序获得。

Linux驱动学习笔记(6)信号量(semaphore)与互斥量(mutex)【转】的更多相关文章

  1. linux 驱动学习笔记01--Linux 内核的编译

    由于用的学习材料是<linux设备驱动开发详解(第二版)>,所以linux驱动学习笔记大部分文字描述来自于这本书,学习笔记系列用于自己学习理解的一种查阅和复习方式. #make confi ...

  2. Linux 驱动学习笔记05--字符驱动实例,实现一个共享内存设备的驱动

    断断续续学驱动,好不容易有空,做了段字符驱动的例子.主要还是跟书上学习在此记录下来,以后说不定能回过头来温故知新. 首先上驱动源码 gmem.c: /************************* ...

  3. linux驱动学习笔记---实现中断下半部以及驱动编写规范(七)【转】

    转自:https://blog.csdn.net/weixin_42471952/article/details/81609141 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协 ...

  4. linux 驱动学习笔记04--简单驱动

    首先贴代码helloworld.c和Makefile /************************************************************************ ...

  5. linux 驱动学习笔记03--Linux 内核的引导

    如图所示为 X86 PC 上从上电/复位到运行 Linux 用户空间初始进程的流程.在进入与 Linux相关代码之间,会经历如下阶段. ( 1 ) 当系统上电或复位时, CPU 会将 PC 指针赋值为 ...

  6. 小松之LINUX 驱动学习笔记(二)

    这两天一直在看字符驱动那块,后来从网上找啦几个例子,自己编译啦下,安装啥的都挺正常,就是用测试程序测试的时候总出问题,现在找到一个能测试的代码,自己先看看和原来的那个代码有啥不同,后面会继续更新,说下 ...

  7. 小松之LINUX 驱动学习笔记(一)

    本篇主要是讲解驱动开发的基础知识以及一些环境配置方面的问题. 下面是一个hello world的简单的模块代码,很简单./*********************** 模块的简单例子* author ...

  8. linux 驱动学习笔记02--应用实例:在内核中新增驱动代码目录和子目录

    下面来看一个综合实例,假设我们要在内核源代码 drivers 目录下为 ARM 体系结构新增如下用于 test driver 的树型目录:| --test  | -- cpu  | -- cpu.c ...

  9. 小松之LINUX驱动学习笔记之模块间函数调用通讯

    1. 符号导出函数 EXPORT_SYMBOL() EXPORT_SYMBOL标签内定义的函数对全部内核代码公开,不用修改内核代码就可以在您的内核模块中直接调用. EXPORT_SYMBOL_GPL( ...

随机推荐

  1. How to Detect and Track Object With OpenCV

    http://www.intorobotics.com/how-to-detect-and-track-object-with-opencv/

  2. 8月17日 Power-BI关于全国房地产开发投资情况分析 QQ群视频交流开课啦

    <ignore_js_op> 数读|中国的经济只剩下房地产了么? 引言: 近日一则标题为“房奴们又立功啦,7月份新增贷款几乎都来自房贷!”的报道吸引了大众的目光.该报道指出在央行8月13日 ...

  3. Java遇见HTML——JSP篇之JavaBeans

    一.JavaBean简介及设计原则 设计原则:公有类.无参的公有构造方法.属性私有.有getter and setter方法 实例: 二.Jsp动作元素 JSP动作标签分为五大类: 三.在JSP页面中 ...

  4. Java遇见HTML——JSP篇之JSP内置对象(下)

    一.什么是session 1.session表示客户端与服务器的一次会话2.Web中的session指:用户在浏览某个网站时,从进入网站到浏览器关闭所经过的这段时间,也就是用户浏览这个网站所花费的时间 ...

  5. javascript设计模式学习之八_发布订阅(观察者)模式

    一.发布订阅模式定义 jQuery中的callbacks,defered,promise本质上就是发布订阅模式的实现.ES6的promise内部实现未开源,不了解具体机制 发布订阅模式又叫做观察者模式 ...

  6. UIButton属性

    1.UIButton状态: UIControlStateNormal          // 正常状态    UIControlStateHighlighted     // 高亮状态    UICo ...

  7. Java基础之创建窗口——使用网格布局管理器(TryGridLayout)

    控制台程序. 网格布局管理器可以在容器的矩形网格中布局组件. import javax.swing.*; import java.awt.*; import javax.swing.border.Et ...

  8. java Servlet中的过滤器Filter

    web.xml中元素执行的顺序listener->filter->struts拦截器->servlet. 1.过滤器的概念 Java中的Filter 并不是一个标准的Servlet ...

  9. 为benchmarksql的PostgreSQL java驱动进行升级

    为benchmarksql的PostgreSQL java驱动进行升级[root@minion1 benchmarksql-4.1.0]# wget https://jdbc.postgresql.o ...

  10. HUD 5086 Revenge of Segment Tree(递推)

    http://acm.hdu.edu.cn/showproblem.php?pid=5086 题目大意: 给定一个序列,求这个序列的子序列的和,再求所有子序列总和,这些子序列是连续的.去题目给的第二组 ...