Linux用戶層多線程無鎖化原子操作

最近由於項目需要,需要將原先使用的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






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章