转自: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. POJ 1032问题描述

    Description New convocation of The Fool Land's Parliament consists of N delegates. According to the ...

  2. install 命令用法详解

    install 命令用法详解 http://man.linuxde.net/install install命令的作用是安装或升级软件或备份数据,它的使用权限是所有用户.install命令和cp命令类似 ...

  3. Linux中硬件相关命令

    http://www.cnblogs.com/cchust/p/3354570.html http://www.cnblogs.com/kerrycode/archive/2012/07/06/257 ...

  4. ios推送

    1. ios 在杀掉app后,只能接受到系统通知,JPUSH自定义消息不能接受到.系统通知经过实验只能接收到50左右个汉字. 2. 实现方案: 推送的时候,JPUSH推送一个消息,App客户端获取到数 ...

  5. 用 CSS 做轮播图

    对于用 css 实现一个轮播图的缘由,是那时候刚开始接触前端,完全还不懂 js.但是有一个项目(就是一个用来应付面试的作品)需要做一个轮播的效果,当时第一反应就是用 css3 自定义动画 -webki ...

  6. 如何用Java解析CSV文件

    首先看一下csv文件的规则: csv(Comma Separate Values)文件即逗号分隔符文件,它是一种文本文件,可以直接以文本打开,以逗号分隔.windows默认用excel打开.它的格式包 ...

  7. .NET: WPF DependencyProperty

    DependencyProperty and DependencyObject is the core of WPF data binding. We can use this two class t ...

  8. poj: 1003

    简单题 #include <iostream> #include <stdio.h> #include <string.h> #include <stack& ...

  9. UML:组件图

    要搞清楚组件图,必须先搞清楚什么是组件? 组件有以下特点:1.能实现一定功能,或者提供一些服务.2.不能单独运行,要作为系统的一部分来发挥作用.3.在物理上独立的,不是逻辑上的概念.4.可单独维护.可 ...

  10. hdu5255 魔法因子

    题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=5255 首先先预处理出一个p,使得p*因子X等于一个整数,且p最小,设q=p*X. 则题目则可以看成存在 ...