簡體   English   中英

我可以使用cmpxchg16b以原子方式將指針復制到指針和int,同時增加int(原子引用計數)嗎?

[英]Can I use cmpxchg16b to atomically copy a pointer to a pointer and an int, while simultaneously incrementing the int (atomic reference counting)?

我的目標是復制一個指針並原子地增加一個引用計數器, 而不是鎖定 我可以使用cmpxchg16b,或者可能有更簡單的方法嗎? 我對匯編程序很無能為力,所以請原諒任何明顯的錯誤。

編輯 :一些類似這樣 ,但對於這個英特爾架構。 (我仍然試圖看看我是否可以調整dr.dobbs文章中的內容到我的平台。原子操作似乎有點不同)

示例內存

struct MyThing {
  void * pSomeObj;
  uint64_t counter;
__attribute__((aligned(16)));
};

我想做的是這樣的事情。

MyThing* globalSource = ...;

...
MyThing* dest;
//copy the pointer while incrementing counter all in one shot. (to prevent data race where a copy is done and some other thread deletes the pointer before the the counter gets a chance to be updated)
AtomicCopyAndIncrement(dest, globalSource);

從邏輯上講,這就是我想要實現的目標:

bool AtomicCopyAndIncrement(MyThing *dest, MyThing *src) {
    //begin atomic
    dest = src;
    dest->counter++;
    //end atomic
    return true;
}

此功能只是按原樣交換所有內容。 我認為這是對的。

bool AtomicSwap(MyThing *dest, MyThing *src)
{
    bool swap_result;
    __asm__ __volatile__
    (
     "lock cmpxchg16b %0;"  
     "setz       %3;"  

     : "+m" (*dest), "+a" (dest->pSomeObj), "+d" (dest->counter), "=q" (swap_result)
     : "b" (src->pSomeObj), "c" (src->counter)
     : "cc", "memory"
     );
    return swap_result;
}

此函數應該使用src並將其設置為dest,同時遞增在dest中分配的計數器。

bool AtomicCopyAndIncrement(MyThing *dest, MyThing *src)
{
    bool swap_result;
    __asm__ __volatile__
    (
     "lock cmpxchg16b %0;"
     "setz       %3;"
     //all wrong
     : "+m" (*dest), "+a" (dest->pSomeObj), "+d" (dest->counter), "=q" (swap_result)
     : "b" (src->pSomeObj), "c" (src->counter +1)
     : "cc", "memory"
     );
    return swap_result;
}

這會減少計數器,但會將點復制回自身。 我不知道這是否必要, 但我認為這是對的。 編輯我很確定這是錯的。

bool AtomicDecrement(MyThing *dest)
{
    bool swap_result;
    __asm__ __volatile__
    (
     "lock cmpxchg16b %0;"  
     "setz       %3;"  

     : "+m" (*dest), "+a" (dest->pSomeObj), "+d" (dest->counter), "=q" (swap_result)
     : "b" (dest->pSomeObj), "c" (dest->counter -1)
     : "cc", "memory"
     );
    return swap_result;
}

使用場景如下:

線程0:

MyThing* newThing;
do {
  if (newThing) delete newThing;
  newThing = new MyThing;
  newThing->pSomeObj->SomeUpdate();
}
while (AtomicSwap(newThing, globalThing));
//then deal with the memory in newThing

線程1-N:

MyThing *currentThing = new MyThing;
//make currentThing->pSomeObj the same as globalThing->pSomeObj, and increment the counter
AtomicCopyAndIncrement(currentThing, globalThing);

考慮使用std::atomic 如果目標體系結構提供它,它將編譯為128位CAS,並且比內聯匯編程序更清晰,更易於使用,並且更加獨立於平台。

下面是一個示例,您可以使用它來更新指針並以原子方式遞增計數器:

std::atomic<MyThing>* target = ...;
MyThing oldValue = target->load();
MyThing newValue { newPointer, 0 };
do{
    newValue.counter = oldValue.counter+1;
while(target->compare_exchange_strong(oldValue,newValue))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM