使用原子操作实现自旋锁
原子操作
在windows平台有InterlockedCompareExchange原子操作接口。实现对内存的互斥修改
1 2 3 4 5 |
LONG InterlockedCompareExchange( _Inout_ LONG volatile *Destination, _In_ LONG Exchange, _In_ LONG Comparand ); |
如果对函数的解释有点疑惑,可以看一下该函数的大致实现。
1 2 3 4 5 6 7 8 9 10 |
LONG InterlockedCompareExchange(LONG volatile *Destination,LONG Exchange,LONG Comparand) { /*Lock Bus*/ LONG old = *Destination; if (Comparand != Exchage) { *Destination = Exchage; } /*Unlock Bus*/ return old; } |
自旋锁
如果我们所1代表“加锁”,0代表“未加锁”。加锁的过程是将内存值0改成1,所以我们可以利用这特性实现加锁操作和解锁操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
int trylock(LONG * lock) { LONG old; old = InterlockedCompareExchange(lock,1,0); if (old == 0) { /*lock ok*/ return 1; } return 0; /*locked by others*/ } int unlock(LONG * lock) { *lock=0; } |
知道trylock只是尝试去将0改成1,如果之前已经是1说明,锁被占用了。所以我们实现了自旋等待锁被释放。
1 2 3 4 |
void lock(LONG * lock) { while(trylock(lock)); } |
更好的实现,用Sleep切换CPU。
1 2 3 4 5 6 |
void lock(LONG *lock) { while (trylock(lock)) { Sleep(0); } } |
对于基于linux的gcc也是有相应的“比较修改”接口__sync_bool_compare_and_swap(lock, old, set),它的参数与windows的接口有两点不一样,参数不一致,返回类型也不一样。它的trylock的实现:
1 2 3 4 |
int trylock(LONG * lock) { return __sync_bool_compare_and_swap(lock,0,1); } |
example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#ifdef WIN32 #define trylock(x) (InterlockedCompareExchange((long *)x,1,0)==0) #else #define trylock(x) __sync_bool_compare_and_swap((long *)x,0,1) #endif #define initlock(x) ((*x)=0) #define lock(x) while(trylock(x)) #define unlock(x) ((*x)=0) static int global_var; static long glock=0; /*thread 1*/ lock(&glock) global_var=12; unlock(&glock) /*thread 2*/ lock(&glock) global_var=13; unlock(&glock) |