“小涛,你说十一黄金周,火车站,飞机场那些售票体系咋没一个宕掉的呢。你不宕掉也不要紧,来两个卖错票的,说不定哥就去上海看世博,去北京看两小无猜的表妹了…”小王诉苦道。
“晕死..哥轻视你,你说都老大不小的人了,怎样脑子里天天都是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并初始化为0
2)获取原子变量的值
atomic_read(atomic_t *v);//回来原子变量的值
3)原子变量加/减
void atomic_add(int i,atomic_t *v); //原子变量添加i
void atomic_sub(int i,atomic_t *v); //原子变量削减i
4)原子变量自增/自减
void atomic_inc(atomic_t *v); //原子变量加1
void atomic_dec(atomic_t *v); //原子变量减1
5)操作并测验
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位,所谓设置位行将位写为1
2)铲除位
void clear_bit(nr,void *addr); //铲除addr地址的第nr位,所谓铲除位行将位写为0
3)改变位
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 = ATOM%&&&&&%_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社区的开发者们早想到了方法:在自旋锁的基础上进行衍生,详细是怎样回事,且听下回分解(每次说这句话是感觉好爽,这难道便是高手耍酷的趣味..)..