第二章1信号量及各种锁_第1页
第二章1信号量及各种锁_第2页
第二章1信号量及各种锁_第3页
第二章1信号量及各种锁_第4页
第二章1信号量及各种锁_第5页
已阅读5页,还剩24页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

NeusoftInstituteofInformation电子工程系--嵌入式Linux驱动设备开发目录一并发与竞态三自旋锁、读写锁四原子操作、等待队列二信号量并发和它的管理

Linux系统的并发源:多个用户空间进程在运行,它们可能以令人惊讶的方式组合运行你的代码.SMP系统能够同时在不同处理器上执行你的代码.内核代码是可抢占的;你的驱动代码可能在任何时间失去处理器,代替它的进程可能也在你的驱动中运行.设备中断是能够导致你的代码并发执行的异步事件.内核也提供各种延迟代码执行的机制,例如workqueue,tasklet,定时器.这些能够使你的代码在任何时间以一种与当前进程在做的事情无关的方式运行.资源共享的硬规则任何时候一个硬件或软件资源被超出一个单个执行线程共享,并且可能存在一个线程看到那个资源的不一致时,你必须明确地管理对那个资源的存取.

当内核代码创建一个会被内核其他部分共享的对象时,这个对象必须一直存在(并且功能正常)到它知道没有对它的外部引用存在为止.在大部分情况下,你将发现内核为你处理引用计数,但是常常有例外.信号量:是一个单个整型值,结合有一对函数,典型地称为P和V.一个想进入临界区的进程将在相关信号量上调用P;如果信号量的值大于零,这个值递减1并且进程继续.相反,如果信号量的值是0(或更小),进程必须等待(睡眠)直到别人释放信号量.解锁一个信号量通过调用V完成;这个函数递增信号量的值,并且,如果需要,唤醒等待的进程.信号量和互斥体互斥:

阻止多个进程同时在同一个临界区内运行--它们的值将初始化为1.这样的信号量在任何给定时间只能由一个单个进程或者线程持有.以这种模式使用的信号量有时称为一个互斥锁.

几乎所有在Linux内核中发现的信号量都用作互斥.

建立临界区:在任何给定时间只有一个线程可以执行代码.

信号量和互斥体信号量信号量在创建时需要设置一个初始值,表示允许有几个任务同时访问该信号量保护的共享资源,初始值为1就变成互斥锁(Mutex),即同时只能有一个任务可以访问信号量保护的共享资源。2.当任务访问完被信号量保护的共享资源后,必须释放信号量,释放信号量通过把信号量的值加1实现,如果释放后信号量的值为非正数,表明有任务等待当前信号量,因此要唤醒等待该信号量的任务。信号量的实现也是与体系结构相关的,定义在<asm/semaphore.h>中,structsemaphore类型用来表示信号量。1.定义信号量structsemaphoresem;2.初始化信号量voidsema_init(structsemaphore*sem,intval)该函数用于初始化设置信号量的初值,它设置信号量sem的值为val。信号量信号量voidinit_MUTEX(structsemaphore*sem)该函数用于初始化一个互斥锁,即它把信号量sem的值设置为1。voidinit_MUTEX_LOCKED(structsemaphore*sem)该函数也用于初始化一个互斥锁,但它把信号量sem的值设置为0,即一开始就处在已锁状态。定义与初始化的工作可由如下宏一步完成:

DECLARE_MUTEX(name)定义一个信号量name,并初始化它的值为1。

DECLARE_MUTEX_LOCKED(name)定义一个信号量name,但把它的初始值设置为0,即锁在创建时就处在已锁状态。信号量信号量获取信号量 voiddown(structsemaphore*sem)获取信号量sem,可能会导致进程睡眠,因此不能在中断上下文使用该函数。该函数将把sem的值减1,如果信号量sem的值非负,就直接返回,否则调用者将被挂起,直到别的任务释放该信号量才能继续运行。intdown_interruptible(structsemaphore*sem)获取信号量sem。如果信号量不可用,进程将被置为TASK_INTERRUPTIBLE类型的睡眠状态。该函数由返回值来区分是正常返回还是被信号中断返回,如果返回0,表示获得信号量正常返回,如果被信号打断,返回-EINTR。信号量信号量down_killable(structsemaphore*sem)获取信号量sem。如果信号量不可用,进程将被置为TASK_KILLABLE类型的睡眠状态。注:down()函数现已不建议继续使用。建议使用down_killable()或down_interruptible()函数。信号量释放信号量voidup(structsemaphore*sem)该函数释放信号量sem,即把sem的值加1,如果sem的值为非正数,表明有任务等待该信号量,因此唤醒这些等待者。自旋锁自旋锁最多只能被一个可执行单元持有。自旋锁不会引起调用者睡眠,如果一个执行线程试图获得一个已经被持有的自旋锁,那么线程就会一直进行忙循环,一直等待下去,在那里看是否该自旋锁的保持者已经释放了锁,“自旋”就是这个意思。自旋锁spin_lock_init(x)该宏用于初始化自旋锁x,自旋锁在使用前必须先初始化。spin_lock(lock)获取自旋锁lock,如果成功,立即获得锁,并马上返回,否则它将一直自旋在那里,直到该自旋锁的保持者释放。自旋锁spin_trylock(lock)试图获取自旋锁lock,如果能立即获得锁,并返回真,否则立即返回假。它不会一直等待被释放。spin_unlock(lock)释放自旋锁lock,它与spin_trylock或spin_lock配对使用。信号量与自旋锁的使用场合信号量可能允许有多个持有者,而自旋锁在任何时候只能允许一个持有者。当然也有信号量叫互斥信号量(只能一个持有者),允许有多个持有者的信号量叫计数信号量。信号量适合于保持时间较长的情况;而自旋锁适合于保持时间非常短的情况,在实际应用中自旋锁控制的代码只有几行,而持有自旋锁的时间也一般不会超过两次上下文切换的时间,因为线程一旦要进行切换,就至少花费切出切入两次,自旋锁的占用时间如果远远长于两次上下文切换,我们就应该选择信号量。rwlock_t类型,在<linux/spinlokc.h>中定义初始化方法:

rwlock_tmy_rwlock=RW_LOCK_UNLOCKED; /*Staticway*/

rwlock_tmy_rwlock;

rwlock_init(&my_rwlock);/*Dynamicway*/允许多个读进程同时进入临界区;写进程必须互斥访问临界区。

读写锁加锁顺序规则获得多个锁可能是危险的:Lock1和Lock2,代码需要同时都获取,你有一个潜在的死锁.仅仅想象一个线程锁住Lock1而另一个同时获得Lock2.接着每个线程试图得到它没有的那个.2个线程都会死锁.当多个锁必须获得时,它们应当一直以同样顺序获得.

以相反的顺序释放。原子变量对共享变量n_opn_op++;都可能需要加锁。内核提供了一个原子整数类型称为atomic_t

下面的操作为这个类型定义并且保证对于一个SMP计算机的所有处理器来说是原子的。因为它被编译成一条单个机器指令voidatomic_set(atomic_t*v,inti);atomic_tv=ATOMIC_INIT(0);原子变量voidatomic_add(inti,atomic_t*v);voidatomic_sub(inti,atomic_t*v);voidatomic_inc(atomic_t*v);voidatomic_dec(atomic_t*v);intatomic_inc_and_test(atomic_t*v);intatomic_dec_and_test(atomic_t*v);intatomic_sub_and_test(inti,atomic_t*v);

voidset_bit(nr,void*addr);voidclear_bit(nr,void*addr);等待队列在Linux驱动程序设计中,可以使用等待队列来实现进程的阻塞,等待队列可看作保存进程的容器,在阻塞进程时,将进程放入等待队列,当唤醒进程时,从等待队列中取出进程。Linux2.6内核提供了如下关于等待队列的操作:1、定义等待队列wait_queue_head_tmy_queue2、初始化等待队列init_waitqueue_head(&my_queue)3、定义并初始化等待队列DECLARE_WAIT_QUEUE_HEAD(my_queue)等待队列4、有条件睡眠wait_event(queue,condition)当condition(一个布尔表达式)为真时,立即返回;否则让进程进入TASK_UNINTERRUPTIBLE模式的睡眠,并挂在queue参数所指定的等待队列上。wait_event_interruptible(queue,condition)当condition(一个布尔表达式)为真时,立即返回;否则让进程进入TASK_INTERRUPTIBLE的睡眠,并挂在queue参数所指定的等待队列上。等待队列intwait_event_killable(wait_queue_tqueue,condition)当condition(一个布尔表达式)为真时,立即返回;否则让进程进入TASK_KILLABLE的睡眠,并挂在queue参数所指定的等待队列上。等待队列5、无条件睡眠(老版本,建议不再使用)sleep_on(wait_queue_head_t*q)让进程进入不可中断的睡眠,并把它放入等待队列q。interruptible_sleep_on(wait_queue_head_t*q)让

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论