原子整数增量

时间:2013-12-11 17:48:12

标签: c multithreading concurrency increment

让我们有一个递增全局原子整数的函数,然后我们将该值存储在非原子局部变量中

_Atomic int atom = 0 ;

void function( void )
{   
    int a = atom++ ;
}

将上述代码与多个线程一起使用时,a是否始终具有唯一值。如果它会像某些评论者所建议的那样,那么atomic_fetch_add等函数的重点是什么。

3 个答案:

答案 0 :(得分:3)

我不熟悉“_Atomic”关键字。这是新的C ++ 11吗?无论如何,您应该使用内置于大多数平台和cpu体系结构中的原子内在函数。 (ala“锁定添加”在x86中)。

在GCC / Clang上,该函数想要调用__sync_add_and_fetch。在Windows上,它被称为InterlockedIncrement

在一些仍然以i386为目标的gcc架构中,您必须在程序集中手动执行此操作。 (虽然这不适用于真正的80386,但锁定内在函数直到80486才被引入,但我离题了......)

unsigned int xadd_4(volatile void* pVal, unsigned int inc)
{
    unsigned int result;
    unsigned int* pValInt = (unsigned int*)pVal;

    asm volatile( 
        "lock; xaddl %%eax, %2;"
        :"=a" (result) 
        : "a" (inc), "m" (*pValInt) 
        :"memory" );

    return (result);
}

int AtomicIncrement(int* pInt)
{
    COMPILE_TIME_ASSERT(sizeof(int)==4);   
    // InterlockedIncrement
    unsigned int result = xadd_4(pInt, 1) + 1;
    return (int)result;
}

答案 1 :(得分:0)

您可以使用程序集插入,使用CompareAndSwap操作(cas)。 对于intel / gcc,以下示例工作(使用cmpxchg):

static inline uint32_t u32cas(volatile uint32_t *ptr, uint32_t old_val, uint32_t new_val) {
   uint32_t prev_val;
   __asm__ __volatile__("lock; cmpxchgl %k1,%2"
                        : "=a"(prev_val)
                        : "q"(new_val), "m"(*(volatile uint32_t *)(ptr)), "0"(old_val)
                        : "memory");
   return prev_val;
}


uint32_t atom = 0;


void atomic_increment() {
  uint32_t x;
  do {
    x = atom;
  } while(u32cas(&atom, x, x + 1) != x);
}

另外,在FreeBSD上,您可以使用

  

man atomic

答案 2 :(得分:-3)

x++++x只是x=x+1;

的快捷方式

你必须使用一些互斥锁。