最近由於項目需要,需要將原先使用的icu4c由4.x版本升級到5.x,但是利用編譯好的5.x版本的icu4c鏈接庫編譯原先的程序時,報出了類似undefined __sync_sub_and_fetch的錯誤,沒辦法,最後通過查看icu4c的源碼,加入了一些編譯選項,將相關的__sync_xxxx函數默認不使用。
雖然問題解決了,但是第一次接觸到__sync_xxx類型的函數,還是想弄明白它的作用。後來發現這一類函數非常有用,尤其是在做多線程的無鎖化操作時,它感覺就相當與內核裏面使用的atomic_t。
__sync_fetch_and_add系列一共有十二個函數,有加/減/與/或/異或/等函數的原子性操作函數, __sync_fetch_and_add, 顧名思義,現fetch,然後自加,返回的是自加以前的值。以count = 4爲例,調用__sync_fetch_and_add(&count,1),之後,返回值是4,然後,count變成了5.
在用gcc編譯的時候要加上選項 -march=i686(後來發現並不是所有的環境下編譯都需要加這個,比如,在我的Ubuntu 12.04 Intel處理器的環境下,不許要加這個參數)
type __sync_fetch_and_add (type *ptr, type value);
type __sync_fetch_and_sub (type *ptr, type value);
type __sync_fetch_and_or (type *ptr, type value);
type __sync_fetch_and_and (type *ptr, type value);
type __sync_fetch_and_xor (type *ptr, type value);
type __sync_fetch_and_nand (type *ptr, type value);
type __sync_add_and_fetch (type *ptr, type value);
type __sync_sub_and_fetch (type *ptr, type value);
type __sync_or_and_fetch (type *ptr, type value);
type __sync_and_and_fetch (type *ptr, type value);
type __sync_xor_and_fetch (type *ptr, type value);
type __sync_nand_and_fetch (type *ptr, type value);
自己也寫了一個小的測試程序,驗證使用這一類函數和普通線程鎖的效率對比
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/time.h>
int global_int = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void* thread_func(void *arg)
{
int i;
for (i = 0; i < 1000000; i++) {
#ifdef WITH_MUTEX
pthread_mutex_lock(&mutex);
global_int++;
pthread_mutex_unlock(&mutex);
#elif defined WITH_ATOMIC
__sync_add_and_fetch(&global_int, 1);
#else
global_int++;
#endif
}
}
int main()
{
struct timeval start_time, end_time;
gettimeofday(&start_time, NULL);
int proc, i;
proc = sysconf(_SC_NPROCESSORS_ONLN);
if (proc < 0)
exit(1);
pthread_t *threadId = (pthread_t *)malloc(proc*sizeof(pthread_t));
for (i = 0; i < proc; i++) {
pthread_create(&threadId[i], NULL, thread_func, NULL);
}
for (i = 0; i < proc; i++) {
pthread_join(threadId[i], NULL);
}
gettimeofday(&end_time, NULL);
printf("thread number = %d global_int = %d cost time msecond = %ld\n", proc, global_int, (long)((end_time.tv_sec - start_time.tv_sec)*1000 + (end_time.tv_usec - start_time.tv_usec)/1000));
}
使用這一類函數,不許要包含特殊的頭文件,編譯如下:
gcc -DWITH_ATOMIC -o test test.c -pthread
運行結果:
thread number = 4 global_int = 4000000 cost time msecond = 133
而如果使用普通的線程鎖,運行結果如下:
thread number = 4 global_int = 4000000 cost time msecond = 526