<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > arm驅(qū)動(dòng)linux并發(fā)與競(jìng)態(tài)并發(fā)控制

          arm驅(qū)動(dòng)linux并發(fā)與競(jìng)態(tài)并發(fā)控制

          作者: 時(shí)間:2016-11-19 來(lái)源:網(wǎng)絡(luò) 收藏
          《[arm驅(qū)動(dòng)]linux并發(fā)與競(jìng)態(tài)---并發(fā)控制》涉及內(nèi)核驅(qū)動(dòng)函數(shù)五個(gè),內(nèi)核結(jié)構(gòu)體一個(gè),分析了內(nèi)核驅(qū)動(dòng)函數(shù)六個(gè);可參考的相關(guān)應(yīng)用程序模板或內(nèi)核驅(qū)動(dòng)模板五個(gè),可參考的相關(guān)應(yīng)用程序模板或內(nèi)核驅(qū)動(dòng)零個(gè)

          一、并發(fā)與競(jìng)態(tài)

          本文引用地址:http://www.ex-cimer.com/article/201611/318220.htm

          1、并發(fā):多個(gè)執(zhí)行單元同時(shí)被執(zhí)行。例如:同一個(gè)test.out可執(zhí)行程序被n次同時(shí)運(yùn)行
          2、競(jìng)態(tài):并發(fā)的執(zhí)行單元對(duì)共享資源(硬件資源和軟件上的全局變量,靜態(tài)變量等)的訪問(wèn)導(dǎo)致的競(jìng)爭(zhēng)。
          a)靜態(tài)的列子:

          char *p;//全局變量
          // 讀取函數(shù)
          module_drv_read(struct file *file, constchar __user *buf, size_t count, loff_t * ppos)
          {copy_to_user(buf, p, countt);}
          //寫(xiě)入函數(shù)
          module_drv_write(struct file *file, constchar __user *buf, size_t count, loff_t * ppos)
          {copy_from_user(p, buf, countt)}

          如果有兩個(gè)進(jìn)程同時(shí)在運(yùn)行,一個(gè)執(zhí)行read,一個(gè)執(zhí)行write,那么執(zhí)行read的可能會(huì)讀取到第二個(gè)程序的寫(xiě)入值或只讀取到第二個(gè)程序部分寫(xiě)入值。
          二、如何避免競(jìng)態(tài):(有共享就有可能發(fā)生競(jìng)爭(zhēng))
          方法:處理競(jìng)態(tài)的常用技術(shù)是加鎖或者互斥,對(duì)應(yīng)semaphore(旗標(biāo))機(jī)制、spin_lock機(jī)制
          三、信號(hào)量(semaphore)機(jī)制

          1、旗標(biāo)(信號(hào)量)

          旗標(biāo)(信號(hào)量):是一個(gè)整型值,結(jié)合一對(duì)函數(shù)void down(struct semaphore * sem)、void up(struct semaphore *sem),如果旗標(biāo)的值大于0,這個(gè)值將減一并且繼續(xù)進(jìn)程。相反,如果旗標(biāo)的值是0(或者更?。诉M(jìn)程必須等待別的進(jìn)程釋放旗標(biāo),解鎖旗標(biāo)通過(guò)調(diào)用up完成,up函數(shù)會(huì)增加旗標(biāo)的值。
          Tip:Linux內(nèi)核的信號(hào)量在概念和原理上與用戶(hù)態(tài)的信號(hào)量是一樣的,但它不能在內(nèi)核之外使用

          2、信號(hào)量機(jī)制編程

          a)信號(hào)的聲明初始化有兩種方式:方式1宏定義并初始化;方式2動(dòng)態(tài)初始化

          信號(hào)的聲明初始化方式1)宏定義并初始化信號(hào)量的快捷方式

          DECLARE_MUTEX(name)
          DECLARE_MUTEX_LOCKED(name)

          內(nèi)核代碼1)DECLARE_MUTEX和DECLARE_MUTEX_LOCKED他們的內(nèi)核代碼為

          #define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name, 1)
          #define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name, 0)
          //__DECLARE_SEMAPHORE_GENERIC的內(nèi)核代碼
          #define __DECLARE_SEMAPHORE_GENERIC(name,count)
          structsemaphore name = __SEMAPHORE_INITIALIZER (name,count)

          模板一)宏定義初始化方式信號(hào)量模板

          DECLARE_MUTEX(name);//定義信號(hào)量
          down(&name);//加鎖,保護(hù)臨界區(qū)在釋放鎖前,將訪問(wèn)本臨界區(qū)的進(jìn)程加入等待隊(duì)列中
          //....要修改全局變量在這修改.....
          up(&name)//釋放鎖

          信號(hào)的聲明初始化方式2)動(dòng)態(tài)初始化方式

          1、定義信號(hào)量結(jié)構(gòu)體 struct semaphore sem;

          structsemaphore sem;

          結(jié)構(gòu)體一)struct semaphore內(nèi)核源碼

          struct semaphore {
          atomic_t count;//旗號(hào)數(shù)值
          intsleepers;
          wait_queue_head_t wait;//等待隊(duì)列
          };

          2、初始化結(jié)構(gòu)體struct semaphore sem有兩種方式,宏定義初始化與函數(shù)初始化

          初始化結(jié)構(gòu)體sem方式a)用函數(shù)sema_init (struct semaphore *sem, int val)初始化結(jié)構(gòu)體struct semaphore sem。

          內(nèi)核源碼二)sema_init內(nèi)核原型代碼

          static inline void sema_init (structsemaphore *sem, intval)
          {
          atomic_set(&sem->count, val);
          init_waitqueue_head(&sem->wait);
          //如果進(jìn)程調(diào)用down時(shí),發(fā)現(xiàn)信號(hào)量為0時(shí)就將進(jìn)程加入到sem->wait等待隊(duì)列中
          }

          模板二)sema_init初始化模板

          struct semaphore sem;
          sema_init (&sem, 1);一開(kāi)始就將旗標(biāo)置1
          down(&sem);
          up(&sem);

          初始化結(jié)構(gòu)體sem方式b)宏初始化,分為將sem的旗標(biāo)直接初始化為1和0的兩種宏初始化方法

          1)init_MUTEX (struct semaphore *sem)將semaphore的旗標(biāo)初始化為1

          內(nèi)核源碼三)init_MUTEX內(nèi)核原型代碼

          staticinline voidinit_MUTEX (struct semaphore *sem)
          {
          sema_init(sem, 1);//可以看出調(diào)用了上面的sema_init函數(shù)
          // 該函數(shù)用于初始化一個(gè)互斥鎖,即它把信號(hào)量sem的值設(shè)置為1
          }

          2)init_MUTEX_LOCKED (struct semaphore *sem)將semaphore的旗標(biāo)初始化為0

          內(nèi)核源碼四)init_MUTEX_LOCKED內(nèi)核原型代碼

          staticinlinevoidinit_MUTEX_LOCKED (structsemaphore *sem)
          {
          sema_init(sem, 0);
          //該函數(shù)也用于初始化一個(gè)互斥鎖,但它把信號(hào)量sem的值設(shè)置為0,即一開(kāi)始就處在已鎖狀態(tài)。
          }

          模板三)宏初始化模板變量sem

          struct semaphore sem;
          init_MUTEX(&sem);一開(kāi)始就將旗標(biāo)置1
          down(&sem);
          up(&sem);

          四、自旋鎖
          1、 概念:自旋鎖最多只能被一個(gè)可執(zhí)行單元持有。自旋鎖不會(huì)引起調(diào)用者睡眠,如果一個(gè)執(zhí)行線程試圖獲得一個(gè)已經(jīng)被持有的自旋鎖,那么這個(gè)線程就會(huì)一直進(jìn)行忙循環(huán),一直等待下去,在那里看是否該自旋鎖的保持者已經(jīng)釋放了鎖,“自旋”就是這個(gè)意思
          2、自旋鎖的編程步驟a,b,c,d

          a)聲明一個(gè)spinlock_t 變量lock

          spinlock_t lock;

          b)初始化spinlock_t 變量lock

          有兩種初始化方式:宏初始化與函數(shù)初始化

          1)宏初始化方法SPIN_LOCK_UNLOCKED

          spinlock_t lock = SPIN_LOCK_UNLOCKED;

          2)函數(shù)初始化方法spin_lock_init(lock)

          spin_lock_init(lock)

          內(nèi)核源碼五)spin_lock_init的內(nèi)核源碼

          //內(nèi)核源碼spin_lock_init發(fā)現(xiàn)使用SPIN_LOCK_UNLOCKED
          #define spin_lock_init(lock) do{ *(lock) = SPIN_LOCK_UNLOCKED; } while(0)

          c)獲得自旋鎖

          1、獲得自旋鎖,spin_lock(lock) ;如果成功,立即獲得鎖,并馬上返回,否則它將一直自旋在那里,直到該自旋鎖的保持者釋放。

          spin_lock(lock)
          //獲取自旋鎖lock,如果成功,立即獲得鎖,并馬上返回,否則它將一直自旋在那里,直到該自旋鎖的保持者釋放。

          內(nèi)核源碼六)spin_lock(lock)內(nèi)核源碼分析

          //源碼內(nèi)核(可以看出來(lái)spin_lock沒(méi)有獲取鎖,它將一直做while循環(huán))
          spin_lock(lock) _spin_lock(lock)
          #define _spin_lock(lock) __LOCK(lock)
          #define __LOCK(lock) do{ preempt_disable(); __acquire(lock); (void)(lock); } while(0)
          #define preempt_disable() do{ } while(0)
          //preempt_disable做空循環(huán)

          2、試圖獲取自旋鎖函數(shù)的spin_trylock(lock),如果能立即獲得鎖,并返回真,否則立即返回假。它不會(huì)一直等待被釋放。(spin_trylock(lock)不做忙等待)
          d)釋放自旋鎖lock,函數(shù)spin_unlock(lock) 它與spin_trylock或spin_lock配對(duì)使用。

          3、自旋鎖spinlock使用模板

          模板四)自玄鎖模板

          spinlock_t lock;
          spin_lock_init(&lock);
          spin_lock(&lock);
          spin_unlock(&lock);

          Tip:將要保護(hù)的值(全局變量,靜態(tài)變量,硬件資源)放在spin_lock(&lock)與spin_unlock(&lock)之間操作

          spin_lock(&lock);
          //改變要保護(hù)的全局變量或硬件資源或靜態(tài)變量(共享變量)
          spin_unlock(&lock);

          4、特殊使用場(chǎng)景:有些設(shè)備只允許被打開(kāi)一次,那么就需要一個(gè)自旋鎖保護(hù)表示設(shè)備的打開(kāi)和關(guān)閉狀態(tài)的變量count。此處count屬于臨界資源,如果不對(duì)count進(jìn)行保護(hù),當(dāng)設(shè)備打開(kāi)頻繁時(shí),可能出現(xiàn)錯(cuò)誤的count計(jì)數(shù)。

          模板五)只允許被打開(kāi)一次的設(shè)備驅(qū)動(dòng)模板

          intcount = 0;
          spinlock_t lock;
          intxxx_init(void){
          //...其他代碼..
          spin_lock_init(&lock);
          //...其他代碼..
          }
          intxxx_open(structinode *inode, structfile *file){
          spin_lock(&lock);//如果相同程序的進(jìn)程要用open,那么其他進(jìn)程就進(jìn)入忙等到while(1)
          if(count){
          spin_unlock(&lock);
          return-EBUSY;
          }
          count++;
          spin_unlock(&lock);
          //.....
          }
          intxxx_release(structinode *inode, structfile *file){
          //....
          spin_lock(&lock);//關(guān)閉時(shí)也要進(jìn)行spin_lock保護(hù),因?yàn)閏ount是全局變量,要改變count就要加自旋鎖
          count--;
          spin_unlock(&lock);
          //.....
          }

          Tip:linux自旋鎖和信號(hào)量所采用的"加鎖(down)---訪問(wèn)臨界區(qū)(critical section)---釋放鎖"的方式,被稱(chēng)為"互斥三部曲"。

          五、總結(jié):編寫(xiě)對(duì)共享資源(硬件資源和軟件上的全局變量,靜態(tài)變量等)的訪問(wèn)的驅(qū)動(dòng)程序場(chǎng)景,就要考慮避免競(jìng)態(tài)的發(fā)生;避免方法:信號(hào)量(或說(shuō)旗標(biāo),semaphore)機(jī)制與spin_lock機(jī)制(自旋鎖)。

          六、補(bǔ)充:信號(hào)量與自旋鎖對(duì)比
          信號(hào)量可能允許有多個(gè)持有者,而自旋鎖在任何時(shí)候只能允許一個(gè)持有者。當(dāng)然也有信號(hào)量叫互斥信號(hào)量(只能一個(gè)持有者),允許有多個(gè)持有者的信號(hào)量叫計(jì)數(shù)信號(hào)量。
          信號(hào)量適合于保持時(shí)間較長(zhǎng)的情況;而自旋鎖適合于保持時(shí)間非常短的情況,在實(shí)際應(yīng)用中自旋鎖控制的代碼只有幾行,而持有自旋鎖的時(shí)間也一般不會(huì)超過(guò)兩次上下文切換的時(shí)間,因?yàn)榫€程一旦要進(jìn)行切換,就至少花費(fèi)切出切入兩次,自旋鎖的占用時(shí)間如果遠(yuǎn)遠(yuǎn)長(zhǎng)于兩次上下文切換,我們就應(yīng)該選擇信號(hào)量。



          評(píng)論


          技術(shù)專(zhuān)區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();