`
ai_longyu
  • 浏览: 479016 次
社区版块
存档分类
最新评论

Linux 设备驱动 ====> 并发控制 --- 信号量与互斥体

 
阅读更多

信号量

信号量的使用

信号量(semaphore)是用于保护临界区的一种常用方法,他的用法和自旋锁类似,但是,与自旋锁不同的是,当获取不到信号量时,进程不会原地打转,而是进入休眠等状态。

Linux中信号量的操作主要有

1.定义信号量

struct semaphore sem;

2.初始化信号量

void sema_init(struct semaphore *sem, int val);

该函数初始化信号量,并设置信号量sem的值为val,尽管信号量可以被初始化为大于1的值而成为一个计数信号量,但是通常不建议这么去做。

#define init_MUTEX(sem) sema_init(sem, 1)

这个宏用于初始化一个互斥的信号量,把sem的值设置为1.

#define init_MUTEX_LOCKED(sem) sema_init(sem, 0)

初始化一个信号量,值设置为0;

也可以使用如下快捷方式初始化

DELCEAR_MUTEX(name)

DELCEAR_MUTEX_LOCKED(name)

3.获得信号量

void down(struct semaphore *sem);

该函数用于获得信号量sem,它会导致睡眠,因此不能再中断上下文中使用;

int down_interruptible(struct semaphore *sem);

该函数与down类似,因为down进入睡眠状态的进程不能被信号打断,但因为down_interruptible而进入睡眠状态的进程能被信号打断,信号也会导致该函数返回,返回非0;

int down_trylock(struct semaphone *sem);

该函数尝试获得信号量sem,如果能立即获得返回0,否则返回非0,不会导致调用者睡眠,可以再中断上下文中使用。

在使用down_interruptible()获得信号量时,对返回值一般会进行检查,如果非0,通常立即返回 -ERESTARTSYS


4.释放信号

void up(struct semaphore *sem);

该函数释放信号量sem,唤醒等待者。

用法


举例使用信号量实现设备只能被一个进程打开


信号量用于同步

如果信号量初始化为0, 则它可以用于同步,同步意味着一个执行单元的继续执行需要另外一个执行单元完成某事,保证执行的先后顺序。

下面一图说明此事

执行单元A 执行单元B

struct semphore sem;

init_MUTEX_LOCKED(&sem); 代码区域c

代码区域a

down(&sem); <---------激活------ up(&sem)

代码区域b


在执行单元A中,因为互斥量被设置为0,所以在down的时候试图获得信号量,因为得不到而进入休眠,所以代码区域b一直无法执行到,当执行单元B 发生,执行up来释放互斥量,使得执行单元A被唤醒,从而继续往下执行。


完成量用于同步

完成量的用法

1. 定义完成量

struct completion my_compeltion;

2. 初始化completion

init_completion(&my_completion);

or

DECLARE_COMPLETION(my_completion);

3. 等待完成量

下面函数用于等待一个完成量被唤醒

void wait_for_completion(struct completion *c);

4. 唤醒完成量

void completion(struct completion *c);

void completion_all(struct completion *c);

前者只唤醒一个等待的执行单元,后者释放所有等待同意完成量的执行单元。

完成量的同步功能

执行单元A 执行单元B

struct completion com;

init_completion(&com); 代码区域c

代码区域a

wait_for_completion(&com); <---------激活------ completion(&com);

代码区域b


下面举例说明完成量用于同步。

我们还是沿用我们之前的globalmem字符驱动,我们这么来设计我们的代码,在read回调函数最开始的时候,我们等待完成量被激活,在write回调函数的最后我们释放完成量,这样的话,我们先cat globalmem,会等待完成量,只有当我们write之后,完成量才会被释放,这样才会执行读的动作。




重新编译模块,在加载我们的globalmem模块,然后进行测试

我们先cat


发现光标停在那,不动了,因为在等待完成量,然后我们另开一个终端,去echo


当我们往里面写数据之后发现之前的终端有反应了


这样就达到了我们的目的,这里我只是举了一个很简单的例子,个人感觉这个方法设计代码有时候蛮有用处的,特别是当2个驱动之间有一些数据的同步,或者一些设置的同步时,可以利用完成量来设计代码达到同步的效果。


自旋锁 VS 信号量

自旋锁和信号量都是解决互斥问题的基本手段,面对特定的情况,我们要加以选择。

信号量时进程级的,用于多个进程之间对资源的互斥。如果竞争失败,会发生进程上下文切换,因为进程上下文切换的开销比较大,因此,只有当进程占用资源时间较长时,选用信号量才是较好的选择。

所要保护的临界资源访问时间比较短时,用自旋锁是非常方便的,它不会引起进程睡眠而导致上下文切换。

总结:

1. 如果访问临界资源的时间较长,则选用信号量,否则选用自旋锁。

2. 信号量所保护的临界资源区可包含可能引起阻塞的代码,而自旋锁则绝对要避免这样的代码,阻塞意味着需要进程上下文切换,如果进程被切换出去,这个时候如果另外一个进程想获得自旋锁的话,会引起死锁。

3. 信号量存在于进程上下文,因此,如果被保护的资源需要在中断或者软终端情况下使用,则只能选择自旋锁。


互斥体

虽然信号量已经可以实现互斥的功能,而且有一些宏定义可以使用,但在Linux 中还是有一套标准的mutex机制。

定义互斥体并初始化

struct mutex my_mutex;

mutex_init(&my_mutex);

获取互斥体

void inline __sched mutex_lock(struct mutex *lock);

int __sched mutex_lock_interruptible(struct mutex *lock);

int __sched mutex_trylock(struct mutex *lock);

这三个函数与spinlock的几个类似的函数用法相同。

释放互斥体

void __sched mutex_unlock(struct mutex *lock);

mutex的使用方法和信号量用于互斥的场合完全一样


修改我们的globalmem字符驱动增加并发控制

定义初始化信号量


在read/write/ioctl 函数中添加信号量


在读写之前使用down_interruptible检查是否可以获得信号量,若不能直接返回,在读写完成后使用up来释放信号量。

应用程序的测试与之前一样,自行测试。

信号量与互斥体就介绍到这,结束。

=========================================================

mail & MSN :zhangjie201412@live.com

=========================================================


分享到:
评论

相关推荐

    深入浅出Linux设备驱动之并发控制

    在驱动程序中,当多个线程同时访问相同的资源时(驱动程序中的全局变量是一种典型的共享资源),可能会引发\"竞态\",因此...Linux内核中解决并发控制的最常用方法是自旋锁与信号量(绝大多数时候作为互斥锁使用)。

    LINUX设备驱动第三版_588及代码.rar

    信号量和互斥体 completion 自旋锁 锁陷阱 除了锁之外的办法 快速参考 第六章 高级字符驱动程序操作 ioctl 阻塞型I/O poll和select 异步通知 定位设备 设备文件的访问控制 快速参考 第七章 时间、延迟...

    linux设备驱动程序

    信号量和互斥体 completiOn 自旋锁 锁陷阱 除了锁之外的办法 快速参考 ch06.第六章 高级字符驱动程序操作 ioctl 阻塞型I/O poll和select 异步通知 定位设备 设备文件的访问控制 快速参考 ch07.第七章 时间、延迟及...

    linux并发与竞争.pptx

    讲解linux下驱动开发,并发与竞争发生的原理,以及原子操作,自旋锁,信号量,互斥体的使用。ppt纯手工制作,希望对大家有所帮助。

    嵌入式Linux视频教程全套2011新版-国嵌嵌入式培训下载地址

    -国嵌内核驱动进阶班-6-1(LINUX驱动程序介绍).avi -国嵌内核驱动进阶班-6-2(字符设备驱动程序设计).avi -国嵌内核驱动进阶班-6-3(字符设备驱动程序实例分析).avi -国嵌内核驱动进阶班-6-4(竞争与互斥).avi -...

    Android驱动开发权威指南

    第二篇 勿于浮砂筑高台——Linux驱动基础篇 第3章Linux内核综述 3.1 OS基本概念 3.1.1多用户系统 3.1.2用户和组 3.1.3进程 3.1.4 Linux单核架构 3.2 Linux内核综述 3.2.1进程/内核模型综述 3.2.2内存管理综述 3.2.3...

    深入浅出:Linux设备驱动中的并发控制

    并发和竞争发生在两类体系中: ...Linux内核中解决并发控制的方法又中断屏蔽、原子操作、自旋锁、信号量。(后面为主要方式)  中断屏蔽:  使用方法  local_irq_disable() //屏蔽中断  …  

    mini2440国嵌视频教程+课件+工具+软件+镜像+教程源码下载地址

    -国嵌内核驱动进阶班-6-1(LINUX驱动程序介绍).avi -国嵌内核驱动进阶班-6-2(字符设备驱动程序设计).avi -国嵌内核驱动进阶班-6-3(字符设备驱动程序实例分析).avi -国嵌内核驱动进阶班-6-4(竞争与互斥).avi -...

    Linux DeviceDrivers 3rd Edition

    信号量和互斥体 111 completion 116 自旋锁 118 锁陷阱 123 除了锁之外的办法 125 快速参考 132 第六章 高级字符驱动程序操作 137 ioctl 137 阻塞型I/O 149 poll和select 163 异步通知 168 定位设备 172 ...

    linux programming instances网络编程教程 附源代码

    2.3.2 信号量的创建和操作 2.4 共享内存区 2.4.1 共享内存区的数据结构 2.4.2 共享内存区的创建和操作 2.4.3 实例 2.4.4 共享内存区的限制 2.5 本章小结 第3章 传输层协议tcp和udp 3.1 tcp/ip基本框架...

    网络编程教程,很好的一本写linux网络编程书,这是我上传的源码

     2.2.2 信号量的结构和信号量操作函数 . 2.2.3 应用示例  2.3 消息队列  2.3.1 消息队列的结构  2.3.2 消息队列的操作函数  2.3.3 应用示例  2.4 共享内存  2.4.1 共享内存的操作函数...

    《计算机操作系统》期末复习指导

    信号量的值与相应资源的使用情况有关。当它的值大于0时,表示当前可用资源的数量;当它的值小于0时,其绝对值表示等待使用该资源的进程个数。注意信号量的值仅能由PV操作来改变。 一般来说,信号量S 0时,S表示...

    操作系统教程 孙钟秀主编

    最后介绍了Windows2000/XP 的同步和通信机制,Linux的信号量机制。CH4 存储管理。讨论存储管理的基本功能、各种传统存储管理技术、虚拟存储管III理技术和最新的存储管理技术如:多级页表、反置页表等。实例研究深入...

    操作系统实验

    在Linux系统下,使用与文件相关的系统调用实现对物理设备文件的读写,参照Linux系统源代码以及Grub系统的源代码,对不同介质上的FAT格式文件系统进行分析。要求在Linux环境下设计出C语言程序,实现以下功能: 1)...

    linux网路编程 中文 23M 版

    1.3 Linux 与 U N I X 的异同.................................................. 5 1 . 4 操作系统类型选择和内核版本的选择..................................... 5 1.4.1常见的不同公司发行的Linux异同...........

    操作系统原理 计算机

    1.5.4 自由软件和Linux 操作系统............................................................................................45 1.5.5 IBM系列操作系统.........................................................

Global site tag (gtag.js) - Google Analytics