2013-01-10 40 views
1

我需要自己用基於GCC 3.4的彙編語言編寫__sync_fetch_and_sub原子操作的實現,它沒有__sync_fetch_and_sub內建函數。但我對裝配知之甚少。如何在基於Linux GCC的彙編語言中實現__sync_fetch_and_sub原子操作GCC

任何人都可以幫助我嗎?任何幫助將不勝感激!!

這裏是__sync_fetch_and_add

inline unsigned int __sync_fetch_and_add(volatile unsigned int* p, unsigned int incr) 
{ 

    unsigned int result; 
    __asm__ _volatile_ ("lock; xadd %0, %1" : 
      "=r"(result), "=m"(*p): 
      "0"(incr), "m"(*p) : 
      "memory"); 
    return result; 
} 

__sync_fetch_and_add(int *ptr, int a_count)是原子添加到A_COUNT ptr指向的變量實施。返回先前在內存中的值。

__sync_fetch_and_sub(int *ptr, int a_count)是從ptr指向的變量中自動減去a_count。返回先前在內存中的值。

+1

'__sync_fetch_and_add(ptr,-a_count)'不會做這項工作嗎? –

+0

我以爲這不起作用,因爲第二個參數是unsigned int,所以如果我們傳遞-a_count,那麼傳遞的值將不會是我們想要的值。但現在我認爲這也適用於這種情況。謝謝。但我把另一個標記爲答案,因爲我想知道如何用匯編語言來實現它。 – Steve

回答

3

這段代碼使用xadd的原子版本:交換和添加:它原子地向右(這裏是內存)添加右操作數並返回右操作數內存中的初始值。在確保操作的原子性之前,先聲明lock聲明。

但是,gcc使用AT & T表示法,所以本說明中的左右參數(取自英特爾手冊)相反。

至於有基於英特爾架構的無xsub指令,來模擬這種最簡單的方法是首先把你想要。減去,然後添加數/交換其原子的反面:

inline unsigned int __sync_fetch_and_sub(volatile unsigned int* p, 
    unsigned int decr) 
{ 
    unsigned int result; 

    __asm__ __volatile__ ("lock; xadd %0, %1" 
      :"=r"(result), "=m"(*p) 
      :"0"(-decr), "m"(*p) 
      :"memory"); 
    return result; 
} 

我也刪除 unsigned屬性,我不覺得它們在這種情況下是相關的。

+0

糾正我,如果我錯了,但'xadd'是互鎖的,不管你是否給它一個'lock'前綴,對吧?另外,爲什麼你需要''內存''clobber? – tmyklebu

+0

@tmyklebu [intel手冊](http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html)顯示「這個指令可以與'LOCK一起使用'前綴以允許指令被自動執行「。我認爲正常的指令被分成多個微操作,並可能導致多核上下文中的非原子行爲(但不確定它是唯一的情況)。至於「記憶」這件事,我承認我很懶惰,並以OP的代碼作爲起點。我會看看你是否可以擺脫它。 – lbonn

+0

@tmyklebu我查了一下'memory'的clobber,並從osdev中找到了[handy doc](http://wiki.osdev.org/Inline_Assembly#Clobbered_Registers_List)。 gcc喜歡優化內聯彙編,並且建議在做內存寫操作時使用'_volatile_'和clobber'「memory」'。不知道這裏是否真的很重要,但最好是安全的,而不是對不起,我猜想:)。 – lbonn