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

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > x86和arm架構(gòu)原子操作的區(qū)別

          x86和arm架構(gòu)原子操作的區(qū)別

          作者: 時(shí)間:2016-11-09 來源:網(wǎng)絡(luò) 收藏
          x86arm原子操作上有些差別,下面一代碼的形式來說明區(qū)別:
          首先比較單核:
          由于x86是CISC指令集,允許在一條指令里進(jìn)行兩次內(nèi)存操作,所以對(duì)i++,i__這些操作在單核條件下是原子,當(dāng)然必須得是顯示使用addl r,%1這種,就可在一條指令里完成讀,寫操作。
          而arm屬于RISC指令集,在一次指令執(zhí)行期間只能有一次內(nèi)存操作,所以像i++,i--這些需要先讀取內(nèi)存值然后賦值的操作,在arm架構(gòu)下沒法一條指令完成,所以就不滿足原子操作,這時(shí)怎樣實(shí)現(xiàn)原子操作呢:
          我們通過代碼來看;
          對(duì)于atomic_add
          x86的實(shí)現(xiàn)很簡(jiǎn)單:

          static__inline__voidatomic_add(inti,atomic_t*v)
          {
          __asm____volatile__(
          LOCK"addl %1,%0"
          :"=m"(v->counter)
          :"ir"(i),"m"(v->counter));
          }

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

          單核情況下LOCK是空。
          下面再看下atomic_add_and_test:

          static__inline__inthal_atomic_add_and_test(inti,emcos_atomic_t*v)
          {
          unsignedcharc;

          __asm____volatile__(
          LOCK"addl %2,%0; sete %1"
          :"=m"(v->val),"=qm"(c)
          :"ir"(i),"m"(v->val):"memory");
          returnc;
          }


          可能大家會(huì)想,這個(gè)有兩條指令了,能是原子的嗎?肯定是,為什么是呢?
          大家要注意sete %1這個(gè)是條件指令,而這個(gè)條件(cflags)是進(jìn)程相關(guān)的,即使當(dāng)進(jìn)程執(zhí)行完add1 %2,%0,這時(shí)發(fā)生中斷,切換到另外一個(gè)進(jìn)程,當(dāng)回來的時(shí)候cflags還是進(jìn)程的,和沒切換的情形一樣,所以是原子。
          而對(duì)于arm這需要更多工作:

          #defineatomic_add(i,v)(void)atomic_add_return(i,v)

          staticinlineintatomic_add_return(inti,atomic_t*v)
          {
          unsignedlongflags;
          intval;

          local_irq_save(flags);
          val=v->counter;
          v->counter=val+=i;
          local_irq_restore(flags);

          returnval;
          }


          上面可以看出是通過關(guān)中斷來實(shí)現(xiàn)的,為什么要關(guān)中斷來實(shí)現(xiàn)原子操作:
          分析下:
          arm對(duì)于i++會(huì)生成如下代碼:
          1ldr r0,=i
          2mov [r0],r1 //這個(gè)讀內(nèi)存操作
          3inc r1 //如果在這個(gè)時(shí)候發(fā)生中斷,然后在中斷處理程序中也執(zhí)行i++操作就不是原子操作
          4mov r1,[r0]//這個(gè)寫內(nèi)存操作
          假設(shè)I=0。如果進(jìn)程1執(zhí)行i++,執(zhí)行到3時(shí)被中斷打斷,然后中斷中也執(zhí)行了i++,當(dāng)兩個(gè)i++執(zhí)行完了,i=1,而不是我們所要的2,這就是非原子操作的結(jié)果。
          怎么解決,就是說2-4這段代碼要么不執(zhí)行,要么執(zhí)行完才能保證原子,這個(gè)在單核上通過關(guān)中斷就可以實(shí)現(xiàn),這也是上面關(guān)中斷的原因。

          2.多核情況;
          x86架構(gòu)下:
          單指令也不是原子操作了,比如addl r,%1這種有兩次內(nèi)存操作的也不是原子操作,有可能在執(zhí)行下一次內(nèi)存操作的時(shí)候,另一個(gè)核心也讀取了這個(gè)內(nèi)存,也會(huì)造成兩次i++操作為1的錯(cuò)誤結(jié)果。
          解決方法是家LOCK標(biāo)識(shí),這個(gè)標(biāo)識(shí)的作用是在一條指令執(zhí)行時(shí),鎖住總線,其他核心沒法讀取,從而得到了原子操作。
          arm架構(gòu)下:
          arm只有v6系列后的才有多核,也才有專門的內(nèi)存原子操作機(jī)制就是ldrex,strex指令。
          其源碼如下:

          staticinlineintatomic_add_return(inti,atomic_t*v)
          {
          unsignedlongtmp;
          intresult;

          __asm____volatile__("@ atomic_add_returnn"
          "1: ldrex %0, [%2]n"
          " add %0, %0, %3n"
          " strex %1, %0, [%2]n"
          " teq %1, #0n"
          " bne 1b"
          :"=&r"(result),"=&r"(tmp)
          :"r"(&v->counter),"Ir"(i)
          :"cc");

          returnresult;
          }




          關(guān)鍵詞: x86arm架構(gòu)原子操

          評(píng)論


          技術(shù)專區(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); })();