You don’t want to mess around with assembly language, especially since you want your code to run on both x86 and ARM. Therefore, compilers let you access these instructions with built-in functions. On gcc, example functions are __sync_fetch_and_add() and __sync_bool_compare_and_swap(). They work just as well on x86 as ARM. Microsoft has similar intrinsics for their compilers.
__sync_fetch_and_add和__sync_bool_compare_and_swap在OceanBase中的应用见:
[xiaochu@OceanBase src]$ grep __sync_fetch_and_add * -nr
common/ob_memory_pool.cpp:212: __sync_fetch_and_add(&mem_size_default_mod_, delta);
common/ob_memory_pool.cpp:220: __sync_fetch_and_add(&mem_size_each_mod_[real_mod_id], delta);
common/ob_lighty_queue.cpp:81: val = __sync_fetch_and_add(&val_, 1);
common/ob_lighty_queue.cpp:112: val = __sync_fetch_and_add(&val_, -1);
common/ob_lighty_queue.cpp:217: uint64_t seq = __sync_fetch_and_add(&push_, 1);
common/ob_lighty_queue.cpp:225: uint64_t seq = __sync_fetch_and_add(&pop_, 1);
common/cmbtree/qlock.h:56: return __sync_fetch_and_add(ref, 1);
common/cmbtree/qlock.h:61: return __sync_fetch_and_add(ref, -1);
common/qlock.h:41: return __sync_fetch_and_add(ref, 1);
common/qlock.h:46: return __sync_fetch_and_add(ref, -1);
common/ob_simple_tpl.h:150: __sync_fetch_and_add(&allocated_, size);
common/futex_sem.cpp:80: if (__sync_fetch_and_add(&p->val_, 1) >= INT_MAX)
common/futex_sem.cpp:102: __sync_fetch_and_add(&p->nwaiters_, 1);
common/futex_sem.cpp:119: __sync_fetch_and_add(&p->nwaiters_, -1);
common/futex_sem.cpp:132: __sync_fetch_and_add(&p->nwaiters_, 1);
common/futex_sem.cpp:155: __sync_fetch_and_add(&p->nwaiters_, -1);
updateserver/ob_inc_seq.h:83: pthread_setspecific(key_, (void*)(ref = read_ref_[__sync_fetch_and_add(&thread_num_, 1) % N_THREAD]));
[xiaochu@OceanBase src]$ grep __sync_bool_compare_and_swap * -nr
common/ob_atomic_type.h:56: || !__sync_bool_compare_and_swap(&modify_version_, old_version, -1))
common/ob_atomic_type.h:66: && !__sync_bool_compare_and_swap(&modify_version_, -1, old_version+1))
common/ob_lighty_queue.cpp:49: while((x = *p) > 0 && !__sync_bool_compare_and_swap(p, x, x - 1))
common/ob_lighty_queue.cpp:57: while((x = *p) <= 0 && !__sync_bool_compare_and_swap(p, x, x + 1))
common/ob_lighty_queue.cpp:143: while(!__sync_bool_compare_and_swap(&data_, NULL, data))
common/ob_lighty_queue.cpp:158: while(NULL == (data = data_) || !__sync_bool_compare_and_swap(&data_, data, NULL))
common/utility.h:380: } while((tmp_seq & 1) || !__sync_bool_compare_and_swap(&seq_, tmp_seq, tmp_seq + 1));
common/utility.h:406: locked_ = (0 == ((cur_seq = seq_) & 1)) && __sync_bool_compare_and_swap(&seq_, cur_seq, cur_seq + 1);
common/ob_tc_malloc.cpp:28: if (__sync_bool_compare_and_swap(&init_lock, 0, 1))
common/ob_tc_malloc.cpp:33: __sync_bool_compare_and_swap(&init_lock, 1, 0);
common/ob_tc_malloc.cpp:38: __sync_bool_compare_and_swap(&init_lock, 1, 2);
common/ob_switch.h:93: return __sync_bool_compare_and_swap(&seq_, seq, (seq&~STATE_MASK) + STATE_MASK + 1);
common/ob_switch.h:98: return __sync_bool_compare_and_swap(&seq_, seq, seq | SWITCH_OFF);
common/ob_switch.h:103: return __sync_bool_compare_and_swap(&seq_, seq, seq | SWITCH_REQ_OFF);
common/cmbtree/qlock.h:36:#define CAS(x, old_v, new_v) __sync_bool_compare_and_swap(x, old_v, new_v)
common/qlock.h:84: else if (!__sync_bool_compare_and_swap(&uid_, 0, uid))
common/qlock.h:113: else if (!__sync_bool_compare_and_swap(&uid_, 0, uid|EXCLUSIVE_BIT))
common/qlock.h:203: if (__sync_bool_compare_and_swap(&uid_, 0, uid|EXCLUSIVE_BIT))
common/qlock.h:235: if (__sync_bool_compare_and_swap(&uid_, 0, uid|EXCLUSIVE_BIT))
common/qlock.h:284: else if (__sync_bool_compare_and_swap(&uid_, cur_uid, uid|EXCLUSIVE_BIT))
common/ob_seq_queue.cpp:115: else if (!__sync_bool_compare_and_swap(&pitem->seq_, -1, -2))
common/ob_seq_queue.cpp:170: else if (__sync_bool_compare_and_swap(&seq_, seq, seq + 1))
common/futex_sem.cpp:34: while((x = *p) > 0 && !__sync_bool_compare_and_swap(p, x, x - 1))
updateserver/ob_inc_seq.h:108: while(!__sync_bool_compare_and_swap(&write_uid_, 0, 1))
__sync_bool_compare_and_swap
Purpose
This function compares the value of __compVal with the value of the variable that __p points to. If they are equal, the value of __exchVal is stored in the address that is specified by __p; otherwise, no operation is performed.
A full memory barrier is created when this function is invoked.
Prototype
bool __sync_bool_compare_and_swap (T* __p, T __compVal, T __exchVal, ...);
where T is one of the data types listed in Supported data types.
Parameters
-
__p
- The pointer to a variable whose value is to be compared with. __compVal
- The value to be compared with the value of the variable that __p points to. __exchVal
- The value to be stored in the address that __p points to.
Return value
If the value of __compVal and the value of the variable that __p points to are equal, the function returns true; otherwise, it returns false.