c++ - 我可以使用 cmpxchg16b 以原子方式将指针复制到指针和 int,同时递增 int(原子引用计数)吗?

标签 c++ multithreading assembly concurrency

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

编辑:类似this的东西,但对于这种英特尔架构。 (我仍在尝试看看我是否可以将 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;
}

这会减少计数器,但会将点复制回自身。我不知道这是否有必要,但我认为这是正确的。 edit 我很确定这是错误的。

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))

关于c++ - 我可以使用 cmpxchg16b 以原子方式将指针复制到指针和 int,同时递增 int(原子引用计数)吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24726460/

相关文章:

c++ - Linux C++ GUI编程工具

c++ - 如何使用自定义修改的 v8::Arguments 调用 v8::Function?

java - 无法创建新的 native 线程错误 - 但使用的线程很少

c - Makefile递归地包含目标文件列表

assembly - 是否可以访问键盘 Controller 的内部通断代码缓冲区?

c++ - 打印奇数

c# - C#和C++之间的进程间通信

multithreading - 用户级线程的好处

android - 在 Android 中解压文件时手机挂起

c - 将汇编语言转换为C语言代码