C++ 我是否可以使用cmpxchg16b以原子方式复制指向指针和int的指针,同时递增int(原子引用计数)?

C++ 我是否可以使用cmpxchg16b以原子方式复制指向指针和int的指针,同时递增int(原子引用计数)?,c++,multithreading,assembly,concurrency,C++,Multithreading,Assembly,Concurrency,我的目标是复制指针并以原子方式递增引用计数器,而不锁定。我可以使用cmpxchg16b吗,或者有一种更简单的方法?我对汇编程序一无所知,所以请原谅任何明显的错误 编辑:类似于,但适用于此英特尔体系结构。(我还在试着看看我是否能将dobbs博士文章中的内容应用到我的平台上。原子操作似乎做得有点不同) 示例存储器 struct MyThing { void * pSomeObj; uint64_t counter; __attribute__((aligned(16))); }; 我想做的

我的目标是复制指针并以原子方式递增引用计数器,而不锁定。我可以使用cmpxchg16b吗,或者有一种更简单的方法?我对汇编程序一无所知,所以请原谅任何明显的错误

编辑:类似于,但适用于此英特尔体系结构。(我还在试着看看我是否能将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))
std::atomic*目标=。。。;
虚构oldValue=target->load();
虚构新值{newPointer,0};
做{
newValue.counter=oldValue.counter+1;
while(target->compare\u exchange\u strong(旧值、新值))

除非我看错了你的答案,否则我实际上不想做交换。我想做一个原子赋值和增量。Dobbs博士的文章基本上就是我想做的。我想也许我可以用cmpxchg16b做一些技巧来实现这一点。我修改了我的第一个AtomicCopyAndIncrement()列表更清楚。谢谢。@marathon:您在哪里看到交换?您只将
newValue
分配给
oldValue
。这里没有交换!好吧,也许我不明白。看起来您已经分配了一个目标,您正在更改目标。我想做的是预先分配(全局)一个源和未分配的目标,将指针复制到目标并递增。其他线程可以随时调出源,因此这就是为什么这必须是原子的。@marathon:只需首先将源以原子方式读取,方法是将源包装到一个
原子
,然后使用
加载
。然后,您将得到一个local变量不能被另一个线程污染。现在您可以
将\u exchange
此变量与目标进行比较。当然,只有加载和交换是原子的,而不是整个过程。如果不锁定,您无法以原子方式完成整个过程:没有CPU可以处理两个不同的内存位置(源和目标)原子性。@Mave:不保证。只有在体系结构支持的情况下。您可以使用
is\u lock\u free
方法检查是否在不需要锁的情况下执行原子上的操作。