GCC數值原子操做API原理及應用

一.前言

C/C++中數值操做,如自加(n++)自減(n–-)及賦值(n=2)操做都不是原子操做,若是是多線程程序須要使用全局計數器,程序就須要使用鎖或者互斥量,對於較高併發的程序,會形成必定的性能瓶頸。html

.gcc原子操做api

**1.**概要api

爲了提升賦值操做的效率,gcc提供了一組api,經過彙編級別的代碼來保證賦值類操做的原子性,相對於涉及到操做系統系統調用和應用層同步的鎖和互斥量,這組api的效率要高不少。多線程

**2.**n++併發

type __sync_fetch_and_add(type *ptr, type value, ...); // m+n
type __sync_fetch_and_sub(type *ptr, type value, ...); // m-n
type __sync_fetch_and_or(type *ptr, type value, ...);  // m|n
type __sync_fetch_and_and(type *ptr, type value, ...); // m&n
type __sync_fetch_and_xor(type *ptr, type value, ...); // m^n
type __sync_fetch_and_nand(type *ptr, type value, ...); // (~m)&n
/* 對應的僞代碼 */
{ tmp = *ptr; *ptr op= value; return tmp; }
{ tmp = *ptr; *ptr = (~tmp) & value; return tmp; }   // nand

3.++n高併發

type __sync_add_and_fetch(type *ptr, type value, ...); // m+n
type __sync_sub_and_fetch(type *ptr, type value, ...); // m-n
type __sync_or_and_fetch(type *ptr, type value, ...); // m|n
type __sync_and_and_fetch(type *ptr, type value, ...); // m&n
type __sync_xor_and_fetch(type *ptr, type value, ...); // m^n
type __sync_nand_and_fetch(type *ptr, type value, ...); // (~m)&n
/* 對應的僞代碼 */
{ *ptr op= value; return *ptr; }
{ *ptr = (~*ptr) & value; return *ptr; } // nand

4.CAS性能

bool __sync_bool_compare_and_swap (type *ptr, type oldval, type newval, ...);
type __sync_val_compare_and_swap (type *ptr, type oldval, type newval, ...);
/* 對應的僞代碼 */
{ if (*ptr == oldval) { *ptr = newval; return true; } else { return false; } }
{ if (*ptr == oldval) { *ptr = newval; } return oldval; }

.程序實例

1.test.cfetch

例子不是併發的程序,只是演示各api的使用參數和返回。因爲是gcc內置api,因此並不須要任何頭文件。ui

#include <stdio.h>

int main() {
    int num = 0;

    /*
     * n++;
     * __sync_fetch_and_add(10, 3) = 10
     * num = 13
     */
    num = 10;
    printf("__sync_fetch_and_add(%d, %d) = %d\n", 10, 3, __sync_fetch_and_add(&num, 3));
    printf("num = %d\n", num);

    /*
     * ++n;
     * __sync_and_add_and_fetch(10, 3) = 13
     * num = 13
     */
    num = 10;
    printf("__sync_and_add_and_fetch(%d, %d) = %d\n", 10, 3, __sync_add_and_fetch(&num, 3));
    printf("num = %d\n", num);

    /*
     * CAS, match
     * __sync_val_compare_and_swap(10, 10, 2) = 10
     * num = 2
     */
    num = 10;
    printf("__sync_val_compare_and_swap(%d, %d, %d) = %d\n", 10, 10, 2, __sync_val_compare_and_swap(&num, 10, 2));
    printf("num = %d\n", num);

    /*
     * CAS, not match
     * __sync_val_compare_and_swap(10, 3, 5) = 10
     * num = 10
     */
    num = 10;
    printf("__sync_val_compare_and_swap(%d, %d, %d) = %d\n", 10, 3, 5, __sync_val_compare_and_swap(&num, 1, 2));
    printf("num = %d\n", num);

    return 0;
}

.Reference

(1)gcc Atomic-Builtins doc (2)CAS(Compare-and-swap)spa

相關文章
相關標籤/搜索