




已阅读5页,还剩9页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Linux设备驱动程序之并发控制(一)“小涛,你说十一黄金周,火车站,飞机场那些售票系统咋没一个宕掉的呢。你不宕掉也没关系,来两个卖错票的,说不定哥就去上海看世博,去北京看青梅竹马的表妹了”小王抱怨道。“晕死.哥鄙视你,你说都老大不小的人了,怎么脑子里天天都是MM之类的事了,能不能有点男子气概啊.”。“靠,能跟你比啊,你是饱汉不知饿汉饥,要是像你一样十一和”嗯,啊,哼哼.没等他说完,我赶忙塞了双臭袜子(哪天的也记不住了)。“得得,I 服了 you,ok”。“不过话说回来,小王,你说的还真是个问题,想想这样的问题,你和GF两个要去西湖看白娘子,偏偏遇到老天跟你过不去,就只剩下一张票了,你和GF两个谁去“不是吧,我这命苦,好不容易有个GF,应该不会出现的,呵呵 ,如果出现那好办,我和她商量好,咱们一起在晚上12:00一起买票,这样我们两边的售票员怎么看都各自有一张票,我们两个就可以一起了小王狡黠的笑着。“笨,我一口一个盐水喷死你,分明一张票,你们两个同一个时间去两个不同的售票点去买,它还是一张票,怎么可能说去两个不同地方,两个售票员都看到有一张票,然后就把这唯一的一张同时卖给了你们两个人”我打断到。算了,看在室友兼我的最忠实狗仔队员的身份,哥就传授一招只传MM的绝学-Linux设备驱动程序之并发控制。听说过并发没,那你肯定听说过竞争,比如竞争上岗,还有你最熟悉的追MM,这也是竞争。那么并发(concurrency)就是说多个执行单元同时,并行被执行,这多个单元却不巧要同时访问一些资源。这其中要分三种情况: 正所谓:道高一尺,魔高一丈,你孙悟空有72变,人家二郎神还有73变不是。有问题,没关系,找小涛哥不是.呵呵。现在就教你几招以备不时只需:大家不是要竞争吗,那好,总体原则就是不让你竞争:保证一个执行单元在访问共享资源的时候,其他的执行单元被禁止访问,将竞争扼杀在萌芽状态。这就是传说中的对共享资源的互斥访问。出招表一:中断屏蔽(可以保证正在执行的内核执行路径不被中断处理程序抢占,由于Linux内核的进程调度都依赖中断来实现,内核抢占进程之间的竞态就不存在了)使用方法: local_irq_disable() /屏蔽中断 说明:local_irq_disable()和local_irq_enable()都只能禁止和使能本CPU内的中断并不能解决SMP多CPU引发的竞争。 critical section /临界区 local_irq_enable() /开中断 与local_irq_disable()不同,local_irq_save(flags)除了进行禁止中断操作以外,还保证目前CPU的中断位信息,local_irq_save(flags)进行相反的操作。 致命弱点: 由于Linux系统的异步I/O,进程调度等很多重要操作都依赖于中断,在屏蔽中断期间所有的中断都无法处理,因此长时间屏蔽中断是很危险的,有可能造成数据丢失甚至系统奔溃。出招表二:原子操作(忘了是物理还是化学老师拉着我的手说:原子是最小的,不能再分的东西.看多形象,执行过程不能被别的代码路径中断的操作就是原子操作,还想跟我竞争,门都没有)。 分为整形原子和位原子操作。 使用方法一:整形原子操作1)设置原子变量的值 void atomic_set(atomic_t *v, int i);/设置原子变量的值为i atomic_t v = ATOMIC_INIT(0);/定义原子变量v并初始化为02)获取原子变量的值 atomic_read(atomic_t *v);/返回原子变量的值3)原子变量加/减 void atomic_add(int i,atomic_t *v); /原子变量增加i void atomic_sub(int i,atomic_t *v); /原子变量减少i4)原子变量自增/自减 void atomic_inc(atomic_t *v); /原子变量加1 void atomic_dec(atomic_t *v); /原子变量减15)操作并测试 int atomic_inc_and_test(atomic_t *v);/这些操作对原子变量执行自增,自减,减操作后测试是否为0,是返回true,否则返回false int atomic_dec_and_test(atomic_t *v); int atomic_sub_and_test(int i, atomic_t *v);6)操作并返回 int atomic_add_return(int i,atomic_t *v); /这些操作对原子变量进行对应操作,并返回新的值。 int atomic_sub_return(int i, atomic_t *v); int atomic_inc_return(atomic *v); int atomic_dec_return(atomic_t *v);使用方法二:位原子操作。1)设置位 void set_bit(nr, void *addr); /设置addr地址的第nr位,所谓设置位即将位写为12)清除位 void clear_bit(nr,void *addr); /清除addr地址的第nr位,所谓清除位即将位写为03)改变位 void change_bit(nr,void *addr); /对addr地址的第nr位反置4)测试位 void test_bit(nr, void *addr); /返回addr地址的第nr位5)测试并操作位 int test_and_set_bit(nr, void *addr); int test_and_clear_bit(nr, void *addr); int test_and_change_bit(nr, void *addr); 光说不练,不是好汉。这谁说的呢,咋就是记不得呢,看段代码:static atomic_t ato_avi = ATOMIC_INIT(1); /定义原子变量static int ato_open(struct inode *inode, struct file *filp) if (!atomic_dec_and_test(&ato_avi) atomic_inc(&ato_avi); return = - EBUSY; /已经打开 . return 0; /已经打开static int ato_release(struct inode *inode, struct file *filp) atomic_inc(&ato_avi); return 0; 出招表三:自旋锁。正如其名,CPU上将要执行的代码将会执行一个测试并设置某个内存变量的原子操作,若测试结果表明锁已经空闲,则程序获得这个自旋锁继续运行;若仍被占用,则程序将在一个小的循环内重复测试这个测试并设置的操作.这就是自旋。使用方法:1)spinlock_t spin; /定义自旋锁 2)spin_lock_init(lock); /初始化自旋锁 3)spin_lock(lock); /成功获得自旋锁立即返回,否则自旋在那里直到该自旋锁的保持者释放 spin_trylock(lock); /成功获得自旋锁立即返回真,否则返回假,而不是像上一个那样在原地打转 4)spin_unlock(lock);/释放自旋锁自旋锁一般像下边这样使用: spinlock_t lock; spin_lock_init(&lock); spin_lock (&lock); ./临界区 spin_unlock(&lock); 还记的前边说的第一招:中断屏蔽中致命的弱点步,自旋锁就是针对SMP或单个CPU但内核可抢占的情况,对于但CPU和内核不可抢占的系统,自旋锁退化为空操作。还有就是自旋锁解决了临界区不受别的CPU和本CPU内的抢占进程打扰,但是得到锁的代码路径在执行临界区的时候还可能受到中断和底半部的影响。 那咋办呢,天要下雨,娘要嫁人,可二郎神的就是比你孙悟空多了一变,你能咋办,打一架?打不过.所以说嘛,Linux社区的开发者们早想到了办法:在自旋锁的基础上进行衍生,具体是怎么回事,且听下回分解(每次说这句话是感觉好爽,这难道就是高手耍酷的乐趣.).Linux设备驱动程序之并发控制(二)上集说到哪儿了呢?瞧这记性,什么?说到天要下雨,娘要嫁人那段。这是谁在答话,废话,我当然知道讲到这里了,我是说驱动讲到哪里了。算了,不管了.话说Linux开源社区的开发者们做了什么工作呢,很简单:利用spin_lock()/spin_unlock()作为自旋锁的基础,将它们和关中断local_irq_disable()/开中断local_irq_enable(),关底半部local_bh_disable()/开底半部local_bh_enable(),关中断并保存状态字local_irq_save()/开中断并恢复状态local_irq_restore()结合就完成了整套自旋锁机制。唉吆,我的天啊,不是我说你们开源社区的那些家伙们,说个东西为啥要那么费劲,就为了说完上面那些红色的破话,差点没喘过来,本来在上篇就想说你们的好人做到低,送你送到西,嘿嘿.我把上边的关系再帮大家捋捋,免的看着费劲spin_lock_irq() = spin_lock() + local_irq_disable()spin_unlock_irq = spin_unlock() + local_irq_enable()spin_lock_irqsave() = spin_unlock() + local_irq_save()spin_unlock_irqrestore() = spin_unlock() + local_irq_restore()spin_lock_bh() = spin_lock() + local_bh_disable()spin_unlock_bh() = spin_unlock() +local_bh_enable()又是一口气,这是什么年头,挣点点击率,怎么就这么难呢.不过也是没办法的事,上了Linux这条贼船,就要有牺牲我一个,幸福全中国的决心,不然微软的又要嚣张了,今天黑你一次屏,明天断你一次网,就连去网吧,微软还伸手到你面前说:对不起,你的系统是盗版好了,让他们热闹去吧,说说咱们的事。作为Linux驱动程序工程师,你要在心里刻下几条戒律:1)什么叫自旋锁,就是忙等待,当锁不可用时,CPU除了在那儿拼命的执行测试并设置的傻瓜操作外什么都不做,才不管电影中含情脉脉的你是她的谁,她是你的谁的这些事,任你两情相约,也是执手相看泪眼,竟无语凝咽。可见,这是多么的影响系统的性能。2)what?你不懂爱情,不在乎第一条,我晕那就给你来个狠的:处理不好自旋锁可能导致系统死锁(dead lock),系统瘫痪。呵呵怕不,等你哭着闹着要上网而不能时,就怕了。那为啥会这样了,很简单,想想:如果我们不小心在一个递归中使用一个自旋锁,说白了就是一个CPU,它已经获得了这个自旋锁,可还贪心地想第二次获得这个自旋锁,这时就死锁了呗。另外,如果一个进程获得自旋锁之后再阻塞,也是很有可能导致死锁的发生。理论完了,给你来点代码,就当是程序员点的一点交代吧:int device_count = 0; 定义文件打开的次数计数static int device_open(struct inode *inode, struct file *filp) . spinlock(&device_count); if(device_count) /已经打开 spin_unlock(&device_count); return -EBUSY; device_count+; /增加使用计数 spin_unlock(&device_count); . return 0;static int device_release(struct inode *inode, struct file *filp) . spinlock(&device_count ); device_count-; /减少使用计数spin_unlock(&device_count );. return 0; 出招表四:读写自旋锁(防写不防读)找你所说,上面的那招自旋锁看似相当好啊.那是,也不看看是谁教的那我就不明白了,接着你说的例子:你说我买票是吧,售票员看到一张票(读)也没错啊,错在与她把票卖出去的操作上(写),你这可好,这样一来,一旦一个锁住,别人都别想看了,这也太傻瓜了吧.小王不屑的鄙视我。耶呵,看不出来哈,你都知道用脑袋想问题了,以前不是都是要大脚趾计算的吗.什么时候升级换代的.我吃惊的瞪着眼,那好,不拿出点真货你搞不定你了.请看新招之读写自旋锁读写自旋锁:它保留了自锁的概念,但是它规定在读方面同时可以有多个读单元,在写方面,只能最多有一个写进程。当然,读和写也不能同时进行。使用方法:1)初始化读写锁的方法。rwlock_t x; /动态初始化rwlock_t x=RW_LOCK_UNLOCKED;/动态初始化 rwlock_init(&x); 2)最基本的读写函数。 void read_lock(rwlock_t *lock);/使用该宏获得读写锁,如果不能获得,它将自旋,直到获得该读写锁 void read_unlock(rwlock_t *lock);/使用该宏来释放读写锁lock void write_lock(rwlock_t *lock);/使用该宏获得获得读写锁,如果不能获得,它将自旋,直到获得该读写锁 void write_unlock(rwlock_t *lock);/使用该宏来释放读写锁lock 3)和自旋锁中的spin_trylock(lock),读写锁中分别为读写提供了尝试获取锁,并立即返回的函数,如果获得,就立即返回真,否则返回假: read_trylock(lock)和write_lock(lock); 4)硬中断安全的读写锁函数: read_lock_irq(lock);/读者获取读写锁,并禁止本地中断 read_unlock_irq(lock);/读者释放读写锁,并使能本地中断 write_lock_irq(lock);/写者获取读写锁,并禁止本地中断 write_unlock_irq(lock);/写者释放读写锁,并使能本地中断 read_lock_irqsave(lock, flags);/读者获取读写锁,同时保存中断标志,并禁止本地中断 read_unlock_irqrestores(lock,flags);/读者释放读写锁,同时恢复中断标志,并使能本地中断 write_lock_irqsave(lock,flags);/写者获取读写锁,同时保存中断标志,并禁止本地中断 write_unlock_irqstore(lock,flags);写者释放读写锁,同时恢复中断标志,并使能本地中断 5)软中断安全的读写函数: read_lock_bh(lock);/读者获取读写锁,并禁止本地软中断 read_unlock_bh(lock);/读者释放读写锁,并使能本地软中断 write_lock_bh(lock);/写者获取读写锁,并禁止本地软中断 write_unlock_bh(lock);/写者释放读写锁,并使能本地软中断呵呵,小王,看到没有有了这第四招,你刚才的问题就没有了,现在给你一个典型应用吧:rwlock_t lock; /定义rwlockrwlock_init(&lock);/初始化rwlock /读时获取锁read_lock(&lock);./临界资源read_unlock(&lock); /写时获取锁write_lock_irqsave(&lock, flags);./临界资源write_unlock_irqrestore(&lock, flags);Linux设备驱动程序之并发控制(三)算了,既然给你那么多秘籍了,也不在乎这剩下的两三招:出招表五:顺序锁(seqlock)使用顺序锁,读执行单元绝不会被写执行单元阻塞,同时写执行单元也不需要等待所有读执行单元完成读操作后才进行写操作。但是写执行单元之间仍然是互斥的。如果读执行单元在读操作期间,写执行单元已经发生了操作,那么,读执行单元必须重新读取数据,以便确保得到的数据是完整的。致命弱点:顺序锁有一个限制,就是它必须要求被保护的共享资源不含有指针。因为写执行单元可能使得指针失效,但读执行单元如果正要访问该指针,将导致Oops。在Linux内核中。读执行单元设计如下顺序读操作。1)读开始unsigned read_seqbegin(const seqlock_t *s1);read_seqbegin_irqsave(lock, flag);【read_seqbegin_irqsave(lock, flag)=local_irq_save() + read_seqbegin();】2)重读int read_seqretry(const seqlock_t *s1, unsigned iv);read_seqretry_irqrestore(lock, iv, flag);【read_seqretry_irqrestore(lock, iv, flag) = read_seqretry()+ local_irq_restore();】读执行单元使用顺序锁的模式如下:do seqnum = read_seqbegin(&seqlock_a); /读操作代码块 。while(read_seqretry(&seqlock_a, seqnum);在Linux内核中。写执行单元设计如下顺序读操作。1)获得顺序锁void write_seqlock(seqlock_t *s1);int write_ tryseqlock(seqlock_t *s1);write_seqlock_irqsave(lock, flags);【=local_irq_save() + write_seqlock()】write_seqlock_irq(lock);【=local_irq_disable() + write_seqlock()】write_seqlock_bh(lock);【=local_bh_disable() + write_seqlock()】2)释放顺序锁void write_sequnlock(seqlock_t *s1);write_sequnlock_irqrestore(lock, flag);【=write_sequnlock() + local_irq_restore()】write_sequnlock_irq(lock);【=write_sequnlock() + local_irq_enable()】write_sequnlock_bh(lock);【write_sequnlock()+local_bh_enable()】写执行单元使用顺序锁的模式如下:write_seqlock(&seqlock_a);/写操作代码write_sequnlock(&seqlock_a);出招表六:RCU(Read-Copy-Update)对于被RCU保护的共享数据结构,读者不需要获得任何锁就可以访问它,但写者在访问它时首先备份一个副本,然后对副本进行修改,然后对副本进行修改,最后使用一个回调(callback)机制在适当的时机把原来数据的指针重新指向新的被修改的数据。这个时机就是所有引用该数据的CPU都退出对共享数据的操作时。1)读锁定。 2)读解锁。 rcu_read_lock(); rcu_read_unlock();rcu_read_lock_bh(); rcu_read_unlock_bh();使用RCU进行读的模式如下:rcu_read_lock(); /读临界区域rcu_read_unlock()3)与RCU相关的写者函数包括:struct rcu_head struct rcu_head *next;/下一个RCU void (*func)(struct rcu_head *head);/获得竞争条件后的处理函数;synchronize_rcu(void);/阻塞读者,直到所有的读者已经完成读端临界区,写者才可以继续下一步操作synchronize_sched();/等待所有CPU都处在可抢占状态,保证所有中断(不包括软中断)处理完毕void call_rcu(struct rcu_head *head, void (*func)(void *arg),void arg);/不阻塞写者,可以在中断上下文或软中断使用,使用synchronize_rcu的写操作流程如下:DEFINE_SPINLOCK(foo_spinlock);Int a_new;spin_lock(&foo_spinlock);/a_new = a;/write a_new;synchronize_rcu();/a=a_new;spin_unlock(&foo_spinlock);/使用call_rcu的写操作流程如下:struct protectRcu int protect; struct rcu_head rcu;struct protectRcu *global_pr;/一般用来释放老的数据void callback_function(struct rcu_head *r) struct protectRcu *t; t=container_of(r, struct protectRcu, rcu); kfree(t);void write_process() struct protectRcu *t, *old; t = kmalloc (sizeof(*t),GFP_KERNEL);/创建副本 spin_lock(&foo_spinlock); t-protect = xx; old= global_pr; global_pr=t;/用副本替换 spin_unlock(&foo_spinlock); call_rcu(old-rcu, callback_function);Linux设备驱动程序之并发控制(四)出招表七:信号量(信号量其实和自旋锁是一样的,就是有一点不同:当获取不到信号量时,进程不会原地打转而是进入休眠等待状态)Linux系统中与信号量相关的操作主要有一下4种:1)定义信号量 struct semaphore sem;2)初始化信号量 void sema_init (struct semphore *sem, int val); /设置sem为valvoid init_MUTEX(struct semaphore *sem); /初始化一个用户互斥的信号量sem设置为1void init_MUTEX_LOCKED(struct semaphore *sem); /初始化一个用户互斥的信号量sem设置为0DECLARE_MUTEX(name); /该宏定义信号量name并初始化1DECLARE_MUTEX_LOCKED(name); /该宏定义信号量name并初始化03)获得信号量void down(struct semaphore *sem); /该函数用于获取信号量sem,会导致睡眠,不能被信号打断,所以不能在中断上下文使用。int down_interruptible(struct semaphore *sem); /因其进入睡眠状态的进程能被信号打断,信号也会导致该函数返回,这是返回非0。int down_trylock(struct semaphore *sem);/尝试获得信号量sem,如果能够获得,就获得并返回0,否则返回非0,不会导致调用者睡眠,可以在中断上下文使用一般这样使用if(down_interruptible(&sem) return - ERESTARTSYS;4)释放信号量void up(struct semaphore *sem); /释放信号量sem,唤醒等待者信号量一般这样被使用,如下所示:/定义信号量DECLARE_MUTEX(mount_sem);down(&mount_sem);/获取信号量,保护临界区critical section /临界区up(&mount_sem);好了,下边给大家一个例子看看使用信号量来实现设备只能被一个进程打开的例子:static DECLARE_MUTEX(xxx_lock);/定义互斥锁static int xxx_open(struct inode *inode, struct file *filp) if(down_trylock(&xxx_lock) /获得打开锁 return EBUSY; /设备忙 return 0;/成功static int xxx_release(struct inode *inode, struct file *filp) up(&xxx_lock); /释放打开锁 return 0;在上面介绍的有关信号量的操作中,我们提到了一个问题就是信号量的初始化问题,一般对信号量的初始化是没有限制的,但如果信号量被初始化为0,则它可以用于同步,说到这里,就不得不介绍新的一招了出招表八:同步(它意味着一个执行单元的继续执行需要等待另一个执行单元完成其事,保证了执行的先后顺序) 在这个图中,执行单元A执行代码区域b之前,必须等待执行单元B执行完代码单元c,而信号量刚好可辅助完成这一同步过程.这时你可能要问,像这样的同步,在现实中可是常常遇到.比如,报名时必须等前一项完成了才能完成后一项.等等,是不是同步就这么一种方式啊.呵呵,真聪明,小菜终于长大了,成为大菜了.其实,Linux系统提供了一种更好的同步机制-完成量,好吧,看在你求学若渴的份上,就把它一起传授给你了,不收费哦,呵呵出招表九:完成量(completion),它用于一个执行单元等待另一个执行单元执行完某事使用方法:1)定义完成量 struct completion my_completion;2)初始化 init_completion(&my_completion); /要是觉得这两步麻烦,就再给你来个宏即定义又初始化DECLARE_COMPLETION(my_completion);3)等待完成量 void wait_for_completion(structcompletion *c); /等待一个completion被唤醒 wait_for_completion_interruptible(struct completion *c); /可中断的wait_for_completion unsigned long wait_for_completion_timeout(struct completion *x,unsigned long timeout); /带超时处理的wait_for_completion4)唤醒完成量 void complete(struct completion *c); /只唤醒一个等待的执行单元。 void complete_all(struct completion *c); /唤醒所有等待这个完成量的执行单元瞧我这记性,说了这么多,怎么就忘了给出completion结构体呢:struct completion unsigned int done;/标志是否已经做完,未做完就是负值,代表等待个数,完成为0 wait_queue_head_t wait;如果觉得不太理解,不过瘾,就给你来张图: 这下感觉怎样,好多了吧.说句真的,我都没想到,这点东西要将那么久,虽然不愿意,但只能说:欲知后事如何,咱们下回接着再聊.Linux设备驱动程序之并发控制(五)小涛,还有多少啊,你看我本来就开玩笑似的说说火车票,飞机票的事,看MM的事,你在眉飞色舞,鸡飞狗跳的没完了呢”啊?怎么这样呢,本来一个寝室,做人的差别就那么大嗫,平时不好好学习,有问题了问我,给你免费教学,还满腹牢骚,也太不够朋友了吧.我锤着桌子说.朋友,我还不够朋友啊,你没听说吗:朋友为我,两肋插刀,我为朋友,插它两刀.“小王打断我,”听你念经似的,都三个小时了,你瞧,都来五了,怎么,你还想和老易的品三国pk一下谁的剧集.“ 想想我也无语了,太阳起了又落,落了又起;花儿也不知开了几次,都懒得理我了,我也寻思这个并发控制为啥就讲不完呢.后面还有精彩的没说呢,不能在这里就把小王的劲头给扼杀了”好了,你也别唧唧歪歪,嘟嘟伦伦了,我发誓,对灯发誓,如果这节还讲不完,你GF的事,我给你解决了,还不行吗”我是无奈了。“这感情好.”一听到MM的话题,小王总是有说不完的激情,没办法,做人的差距还就是那么大.言归正传,话说出招表十:读写信号量(不是吧,都十了,怪不得小王不耐烦了,这么多招式,相当你,我有九阳神功护体还没这么快呢.哎)“小王,你记得不,我在前边提到过一招,说的是:防读不防写“记得,有MM,我就记得,没有那就好说了.“得得,不问你了,三句不离XXX”传说中:读写信号量可允许N个读执行单元同时访问共享资源,而最多只能有一个写执行单元。“我想起来了,想起来了,就是和前边的那个什么-防出不防进.差不多”想想小王那副口水哈子吊多长的样子,我都懒的理他了.使用方法:1)定义和初始化读写信号量 struct rw_semphore my_rws; /定义读写信号量 void init_rwsem(struct rw_semaphore *sem); /初始化读写信号量 2)读信号量获取 void down_read(struct rw_semaphore *sem); int down_read_try(struct rw_semaphore *sem);3)读信号量释放 void up_read(struct rw_semaphore *sem);4)写信号量获取 void down_write(struct rw_semaphore *sem); int down_write_try(struct rw_semaphore *sem);5)写信号量释放 void up_write(struct rw_semaphore *sem);给个例子吧:rw_semaphore rw_sem;/定义读写信号量init_rwsem(&rw_sem);/初始化读写信号量/读时获取信号量down_read(&rw_sem);./临界资源up_read(&rw_sem);/写时获取信号量down_write(&rw_sem);./临界资源up_write(&rw_sem);说句真的,如果小王赖上我给他找个MM,我还心里真没底,所以吗,下面说最最最最后一招,我也就解放了哦出招表十一:互斥体(啥叫互斥体,怎么感觉前边的都是互斥体,呵呵,确实,只不过Linux开发者们觉得不过瘾,就专门研究了一个互斥体,谁让咱用人家的东西呢)使用方法:1)定义并初始化互斥体 struct mutex my_mutex; mutex_init(&my_mutex); 2)获取互斥体 void fastcall mutex_lock(struct mutex *lock);/引起的睡眠不能被打断 int fastcall mutex_lock_interruptible(struct mutex *lock);/可以被打断 int fastcall mutex_lock_trylock(struct mutex *lock);/尝试获得,获取不到也不会导致进程休眠 3)释放互斥体 void fastcall mutex_unlock(struct mutex *lock);给个例子:struct mutex my_mutex; /定义mutexmutex_init(&my_mutex);mutex_lock(&my_mutex);./临界资源mutex_unlock(&my_mutex);完了,一切都完了,有关并发控制的相关招数都完了,小王也该放心去追MM了,有我这几招,看谁还敢竞争,我也不用愁了,总算在这一集讲完了本不该讲完的东西.如果有需要,我会给大家讲一节有关载入了并发控制的字符设备驱动程序,名字我都想好了-需要的请举手,火热招标中哈.不好意思,人在江湖走,怎能不湿脚,不小心做起广告来了Linux设备驱动程序之并发控制(实例总结篇)小王,小王,别睡了,瞧你,咋还睡着了呢我催促他说.现在是公元前还是公元后啊,我的MM等急了没.呵呵,看他一脸傻笑。提醒各位路过的MM,如果没有男友的,可以联系小王,电话:拐拐拐。“什么,我的,呵呵,没办法,谁让我这有才呢.”算算前边有关并发控制的有关内容,都到五了,一连来了十一招,今天也不好意思再卖官子了,做一个最后的实例总结篇,下一节,就要开始新的内容了哦,没赶上的可要加油了。实例篇:1.定义带有设备并发控制方案的结构体(诸如信号量,自旋锁等,反正前边那么多了)我是一名高手,告诉大家一个高手的习惯,就是喜欢也习惯把将某设备所使用的自旋锁,信号量等辅助手段也放到设备结构体中,就像下边这样:struct csyncontrol_dev struct cdev cdev;/cdev结构体 unsigned char memCSYNCONTROL_SIZE; /设备内存 struct semaphore sem; /用于并发控制的信号量然后,将信号量的初始化工作放到模块初始化部分里int csycontrol_init(void) int result; dev_t devno = MKDEV(global_major,0); /申请设备号 XXXXXX(参照前边Linux设备驱动之简单字符设备驱动(下) csycontrol_setup_cdev(csyncontrol_devp, 0); init_MUTEX(&csyncontrol_devp-sem); /初始化信号量 XXXXXX以后在访问csyncontrol_dev中的共享资源时,需要首先获取这个信号量,访问完成后,随即释放掉这个信号量,比如下面的,写操作:/csycontrol_read函数static ssize_t csycontrol_read(struct file *filp,char
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 提升医院消毒效果的措施与技巧
- 宿迁泽达职业技术学院《公共写作》2023-2024学年第一学期期末试卷
- 贵阳幼儿师范高等专科学校《中国风景园林艺术之源流》2023-2024学年第一学期期末试卷
- 苏州工业职业技术学院《植物生理学》2023-2024学年第一学期期末试卷
- 石家庄铁道大学四方学院《温病学中医耳鼻喉科学》2023-2024学年第一学期期末试卷
- 闽南师范大学《文献查阅与技术文档写作》2023-2024学年第一学期期末试卷
- 胸下段食管癌护理查房
- 2025年医疗美容行业美容整形行业市场布局与竞争优势报告
- 2025年医疗美容行业互联网服务市场细分领域发展报告
- 标准化转运流程
- 核心制度:安全输血制度
- 《中华人民共和国职业分类大典》(2022年版)各行业职业表格统计版(含数字职业)
- 《银行业金融机构安全评估标准》
- 企业内部培训体系搭建及实施效果评估报告
- 湖南省首届财会知识大赛竞赛考试网络答题题库
- 国家开放大学-传感器与测试技术实验报告-实验
- 经皮球囊压迫术治疗三叉神经痛中国专家共识(2022 版)
- 人工智能知到智慧树章节测试课后答案2024年秋复旦大学
- 胸痛中心数据填报培训
- 直臂式高空作业车安全管理
- 水毁道路修复工程项目可行性研究报告
评论
0/150
提交评论