2014-04-10 24 views

回答

2

一个compare_and_swap回路可以使用,如:

// Atomically perform i|=j. Return previous value of i. 
int bitTestAndSet(tbb::atomic<int>& i, int j) { 
    int o = i;     // Atomic read (o = "old value") 
    while((o|j)!=o) {   // Loop exits if another thread sets the bits 
     int k = o; 
     o = i.compare_and_swap(k|j,k); 
     if(o==k) break;  // Successful swap 
    } 
    return o; 
} 

注意,如果在第一次尝试时状态成功,将只有一个获得围栏,而不是一个完整的围栏。是否重要取决于上下文。

如果存在高争用风险,则应该在循环中使用某种退避方案。 TBB在内部为争用管理使用类atomic_backoff,但它目前不是公共TBB API的一部分。

还有第二种方法,如果可移植性不是问题,并且您愿意利用x86平台上tbb :: atomic和T的布局相同的无证事实。在这种情况下,只需使用汇编代码对tbb :: atomic进行操作即可。下面的程序演示了这种技术:

#include <tbb/tbb.h> 
#include <cstdio> 

inline int SetBit(int array[], int bit) { 
    int x=1, y=0; 
    asm("bts %2,%0\ncmovc %3,%1" : "+m" (*array), "+r"(y) : "r" (bit), "r"(x)); 
    return y; 
} 

tbb::atomic<int> Flags; 
volatile int Result; 

int main() { 
    for(int i=0; i<16; ++i) { 
     int k = i*i%32; 
     std::printf("bit at %2d was %d. Flags=%8x\n", k, SetBit((int*)&Flags,k), +Flags); 
    } 
} 
+0

感谢您的回答。我不希望位设置失败。如果我使用CAS,它可能无法设置该位。我想盲目设置位 – arunmoezhi

+0

如果位集失败并重试,它有什么不同?这就好像线程稍后到达一样。并非所有的硬件都具有原子比特集。事实上,如果使用sync_or_and_fetch的结果,gcc会生成一个cmpxchg循环。我假设结果是有趣的,因为问题标题是“测试和设置”,而不仅仅是“设置”。 –

+0

如果机器有硬件BTS指令,那么它会使用'cmpxchg'吗? – arunmoezhi