概念

一个信号量本质是一个整数值,它和一堆函数联合使用,这一对函数通常称为P和V;希望进入临界区的进程将在相关信号量上调用P;如果信号量的值大于零,则该值会减少1,进程可以继续执行;相反,如果信号量的值为0或者更小,则进程必须等待知道其他人释放该信号量;对信号量的解锁通过调用V完成;该函数增加信号量的值,并在必要时唤醒等待的进程;

当信号量用于互斥时(即避免多个进程同时在一个临界区中运行),信号量 的值应该初始化为1;这种信号量在任何给定时刻只能由单个进程或者线程拥有;这种使用模式下,一个信号量有时也成为一个互斥体(mutex),它是互斥的简称;

Linux内核汇总几乎所有的信号量均用于互斥体;

信号量的使用

Linux内核遵守上述语义提供了信号量的实现,要使用信号量,内核代码必须包含<linux/semaphore.h>,相关的类型是struct semaphore;

实际的信号量可以通过集中途径来生命和初始化;

直接创建信号量,其中val参数是赋予一个信号量的初始值;

 static inline void sema_init(struct semaphore *sem, int val)

Linux中P函数被称为down–或者这个名字的变种;该类函数减小了信号量的值,它也许会将调用者置于休眠状态,然后等待信号量变为可用,之后授予调用者对保护资源的访问;作为通常规则,我们不应该使用非中断的操作;down的几个变种函数都有返回值,需要始终进行检查;

Linux中V函数被称为up,该函数增加了信号量的值,使用该函数后,调用者不再拥有该信号量;任何down操作都需要对应进行up操作,特别注意在错误分支中对已持有信号量的释放;

 void down(struct semaphore *sem);
int __must_check down_interruptible(struct semaphore *sem);
int __must_check down_killable(struct semaphore *sem);
int __must_check down_trylock(struct semaphore *sem);
int __must_check down_timeout(struct semaphore *sem, long jiffies);
void up(struct semaphore *sem);
读写信号量的使用

许多任务可以划分成两种不同的工作类型:一些任务只需要读取受保护的数据结构,而其他的则必须做出修改;允许多个并发读取是可能的,只要它们中没有哪个要做修改;这样做可以大大的提高性能,以内容只读任务可以并行的完成它们的工作,而不需要等待其他读取者退出临界区;

内核中为这种情形提供了一种特殊的信号量类型,rwsem,虽然使用比较少,但偶尔也比较有用;

使用rwsem必须包含头文件<linux/rwsem.h>,对应的数据类型是struct rw_semaphore;

在使用之前需要使用init_rwsem宏进行初始化;

 #define init_rwsem(sem)                        \
do { \
static struct lock_class_key __key; \
\
__init_rwsem((sem), #sem, &__key); \
} while ()

down_read系列函数提供了对保护资源的只读访问,可以和其他读取者并发的访问;down_write则提供了对保护资源的写访问,与其他读写着互斥;一个rwsem允许一个写入者和多个读取者拥有该信号量;up_xxx操作则用于释放已经持有的信号量;

 /*
* lock for reading
*/
extern void down_read(struct rw_semaphore *sem); /*
* trylock for reading -- returns 1 if successful, 0 if contention
*/
extern int down_read_trylock(struct rw_semaphore *sem); /*
* lock for writing
*/
extern void down_write(struct rw_semaphore *sem);
extern int __must_check down_write_killable(struct rw_semaphore *sem); /*
* trylock for writing -- returns 1 if successful, 0 if contention
*/
extern int down_write_trylock(struct rw_semaphore *sem); /*
* release a read lock
*/
extern void up_read(struct rw_semaphore *sem); /*
* release a write lock
*/
extern void up_write(struct rw_semaphore *sem); /*
* downgrade write lock to read lock
*/
extern void downgrade_write(struct rw_semaphore *sem);
互斥体的使用

Linux内核互斥体之前是以val为1的信号量存在的,现在已经单独实现;使用互斥体需要包含<linux/mutex.h>头文件;

mutex_init宏完成对互斥量的初始化;

 #define mutex_init(mutex)                        \
do { \
static struct lock_class_key __key; \
\
__mutex_init((mutex), #mutex, &__key); \
} while ()

其中包含了一些列的lock与unlock操作,如下所示,其中mutex_lock_xxx表示在进入临界区之前加锁的操作,mutex_unlock操作表示退出临界区的解锁的操作;

 extern void mutex_lock(struct mutex *lock);
extern int __must_check mutex_lock_interruptible(struct mutex *lock);
extern int __must_check mutex_lock_killable(struct mutex *lock);
extern void mutex_lock_io(struct mutex *lock); # define mutex_lock_nested(lock, subclass) mutex_lock(lock)
# define mutex_lock_interruptible_nested(lock, subclass) mutex_lock_interruptible(lock)
# define mutex_lock_killable_nested(lock, subclass) mutex_lock_killable(lock)
# define mutex_lock_nest_lock(lock, nest_lock) mutex_lock(lock)
# define mutex_lock_io_nested(lock, subclass) mutex_lock(lock)
#endif /*
* NOTE: mutex_trylock() follows the spin_trylock() convention,
* not the down_trylock() convention!
*
* Returns 1 if the mutex has been acquired successfully, and 0 on contention.
*/
extern int mutex_trylock(struct mutex *lock);
extern void mutex_unlock(struct mutex *lock); extern int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock);

Linux设备驱动程序 之 信号量和互斥体的更多相关文章

  1. linux设备驱动程序该添加哪些头文件以及驱动常用头文件介绍(转)

    原文链接:http://blog.chinaunix.net/uid-22609852-id-3506475.html 驱动常用头文件介绍 #include <linux/***.h> 是 ...

  2. 【转】linux设备驱动程序中的阻塞机制

    原文网址:http://www.cnblogs.com/geneil/archive/2011/12/04/2275272.html 阻塞与非阻塞是设备访问的两种方式.在写阻塞与非阻塞的驱动程序时,经 ...

  3. 【APUE】信号量、互斥体和自旋锁

    http://www.cnblogs.com/biyeymyhjob/archive/2012/07/21/2602015.html http://blog.chinaunix.net/uid-205 ...

  4. Linux设备驱动程序学习之分配内存

    内核为设备驱动提供了一个统一的内存管理接口,所以模块无需涉及分段和分页等问题. 我已经在第一个scull模块中使用了 kmalloc 和 kfree 来分配和释放内存空间. kmalloc 函数内幕 ...

  5. linux设备驱动程序-设备树(1)-dtb转换成device_node

    linux设备驱动程序-设备树(1)-dtb转换成device_node 本设备树解析基于arm平台 从start_kernel开始 linux最底层的初始化部分在HEAD.s中,这是汇编代码,我们暂 ...

  6. linux设备驱动程序-设备树(3)-设备树多级子节点的转换

    linux设备驱动程序--设备树多级子节点的转换 在上一章:设备树处理之--device_node转换成platform_device中,有提到在设备树的device_node到platform_de ...

  7. linux设备驱动程序-i2c(2)-adapter和设备树的解析

    linux设备驱动程序-i2c(2)-adapter和设备树的解析 (注: 基于beagle bone green开发板,linux4.14内核版本) 在本系列linux内核i2c框架的前两篇,分别讲 ...

  8. linux设备驱动程序--在用户空间注册文件接口

    linux字符设备驱动程序--创建设备节点 基于4.14内核,运行在beagleBone green 在上一讲中,我们写了第一个linux设备驱动程序--hello_world,在驱动程序中,我们什么 ...

  9. linux设备驱动程序--gpio控制

    gpio驱动程序 上一章节linux设备驱动程序--创建设备节点章节主要介绍了linux字符设备驱动程序的框架,从这一章节开始我们讲解各种外设的控制,包括gpio,i2c,dma等等,既然是外设,那就 ...

随机推荐

  1. 基于【 springBoot +springCloud+vue 项目】三 || 项目部署

    前言 今天所要讲的项目部署,并非正式环境部署,而是作为开发中的测试环境部署.随着项目模块的增多,启动的模块也随之增多,本人的电脑启动四个模块就已经卡的不行了,为了减轻电脑压力,不得不自己学着搭建一个项 ...

  2. C++ STL 之 queue

    queue 是一种先进先出(first in first out, FIFO)的数据类型,他有两个口,数据元素只能从一个口进,从另一个口出.队列只允许从队尾加入元素,队头删除元素,必须符合先进先出的原 ...

  3. 11.SpringMVC注解式开发-处理器方法的返回值

    处理器方法的返回值 使用@Controller 注解的处理器的处理器方法,其返回值常用的有四种类型 1.ModelAndView 2.String 3.void 4.自定义类型对象 1.返回Model ...

  4. linux 使用 rz 上传和 sz下载 命令

    linux系统 root权限 lrzsz安装包 ①.在线安装-执行命令 yum install lrzsz  离线安装-需要提前准备好安装包 编译安装 root 账号登陆后,依次执行以下命令: tar ...

  5. centos所有版本镜像下载地址

    centos所有版本镜像下载地址 版本号 下载地址 更新时间 centos2.1  iso镜像下载 2.1/ 2009/8/19  1:36 centos3.1  iso镜像下载 3.1/ 2005/ ...

  6. Django框架起步

    一.环境安装 二.创建项目 三.项目目录 四.创建项目应用 五.应用目录 六.第一个响应 七.第一个模板页面 八.第一个重定向 九.url应用移植 十.多应用相同模板页面冲突 十一.静态资源的配置 十 ...

  7. 【收藏】linux快速查找文件的技巧

    有时候,我们需要在系统中查找文件,Linux有一个非常优秀的搜寻系统. 一般提到搜寻文件的时候,很多人第一反应是find命令,但其实find不是常用的,因为速度慢,而且毁硬盘.一般我们都先用where ...

  8. Ubuntu系统---WeChat安装

    Ubuntu安装微信教程 工具/原料 ubuntu 14.04 x86 方法/步骤 这次我用的系统是Ubuntu 14.04 x86,在网上先去下载electronic-wechat-linux ht ...

  9. Django 外键、多对多插入数据方法

    models.py class UserInfo(models.Model): username = models.CharField(max_length=64,db_column='usernam ...

  10. gitlab 错误处理

    用gitolite新建项目,clone后首次push,可能会出现: $ git push No refs in common and none specified; doing nothing. Pe ...