[英]why user space atomic_t in gcc(3.4.5) doesn't work
最近在我的工作中,我想在多线程程序中实现一个计数器。 我发现在我的GCC(3.4.5)中有一个名为atomic_t的用户空间数据类型。 但它似乎不是真正的原子。
我在具有12个内核的x86_64机器上测试了atomic_inc()/ atomic_read() ,并且linux内核是2.6.9。
这是演示。 我添加pthread_cond_t和pthread_cond_broadcast来提高并发度。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <pthread.h>
#include <asm/atomic.h>
atomic_t atomic_count;
pthread_cond_t g_cond;
pthread_mutex_t g_mutex;
void* thread_func(void*p) {
pthread_mutex_t* lock = (pthread_mutex_t*)p;
pthread_mutex_lock(lock);
pthread_cond_wait(&g_cond, lock);
pthread_mutex_unlock(lock);
for (int i=0;i<20000;++i){
atomic_inc(&atomic_count);
}
return NULL;
}
#define THRD_NUM 15
int main() {
atomic_set(&atomic_count, 0);
pthread_cond_init(&g_cond, NULL);
pthread_mutex_init(&g_mutex, NULL);
pthread_t pid[THRD_NUM];
for (int i=0; i<THRD_NUM; i++) {
pthread_create(&pid[i], NULL, thread_func, &g_mutex);
}
sleep(3);
pthread_cond_broadcast(&g_cond);
for (int i=0; i<THRD_NUM; i++) {
pthread_join(pid[i], NULL);
}
long ans = atomic_read(&atomic_count);
printf("atomic_count:%ld \n", ans);
}
预期的结果是300000,但我们总是得到270000+或280000+。 我发现atomic_inc()的实现是
static __inline__ void atomic_inc(atomic_t *v)
{
__asm__ __volatile__(
LOCK "incl %0"
:"=m" (v->counter)
:"m" (v->counter));
}
根据intel手册, LOCK前缀具有完全屏障的语义。 这是否意味着程序的输出与指令重新排序无关?
更重要的是,我发现了一个有趣的现象。 如果我将THRD_NUM设置为小于12(我机器的核心编号),则错误频率会降低。 我认为这可能是由上下文切换引起的。 但我不知道这是怎么发生的。 有人能帮我吗? 谢谢!
LOCK是一个宏。 你确定它实际上被定义为“锁定”,因为它应该实际做任何事情吗?
我很确定您使用的是仅用于内核的标头。 “asm”下的内容不应在userland中使用。
我假设<asm/atomic.h>
是一些Linux内核头文件? 它肯定不是C的一部分。 在C11中,你可以通过<stdatomic.h>
获得<stdatomic.h>
。 你需要切换到更新的gcc。
我不知道你从哪里获得LOCK
宏,但我认为它没有被正确定义。 在Linux的asm / atomic.h版本中,我发现谷歌搜索他们使用的是一个名为LOCK_PREFIX
的宏,而不是LOCK
。
这是他们的atomic_inc代码:
93 static inline void atomic_inc(atomic_t *v)
94 {
95 asm volatile(LOCK_PREFIX "incl %0"
96 : "+m" (v->counter));
97 }
这应该变成:
asm volatile("lock incl %0"
: "+m" (v->counter));
我不再烦恼了,只是把字符串放入( "lock incl %0"
)。
然后编译gcc -S myfile.c
并确保在myfile.s
你看到lock incl
指令而不仅仅是一个普通的incl
(没有lock
)。
我相信
atomic_t atomic_count;
应该
volatile atomic_t atomic_count;
试试吧。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.