Linux用户层多线程无锁化原子操作

时间:2021-11-29 12:08:57

最近由于项目需要,需要将原先使用的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