一般地,对于int num
,num++
(或++num
),作为读-修改-写操作中,是不是原子.但我经常看到编译器,例如GCC,为它生成以下代码(在这里尝试):
由于第5行对应于num++
一条指令,我们可以得出结论,在这种情况下num++
是原子的吗?
如果是这样,是否意味着如此生成num++
可以在并发(多线程)场景中使用而没有任何数据争用的危险(例如,我们不需要制作它,std::atomic<int>
并强加相关成本,因为它是无论如何原子)?
UPDATE
请注意,这个问题不是增量是否是原子的(它不是,而且是问题的开头行).它是否可以在特定场景中,即在某些情况下是否可以利用单指令性质来避免lock
前缀的开销.而且,作为公认的答案约单处理器的机器,还有部分提到这个答案,在其评论和其他人谈话解释,它可以(尽管不是C或C++).
暂停指令通常用于测试自旋锁的循环,当一些其他线程拥有自旋锁时,以缓解紧密循环.据说这相当于一些NOP指令.有人能告诉我它是如何适用于自旋锁优化的吗?在我看来,即使是NOP指令也浪费了CPU时间.它们会降低CPU使用率吗?
另一个问题是我可以将暂停指令用于其他类似目的.例如,我有一个忙线程,它不断扫描一些地方(例如队列)以检索新节点; 但是,有时队列是空的,线程只是在浪费cpu时间.睡眠线程并通过其他线程唤醒它可能是一个选项,但线程是关键的,所以我不想让它睡觉.可以暂停指令工作以减轻CPU使用率吗?目前它使用100%cpu的物理核心?
谢谢.
两种常见的锁定习语是:
if (!atomic_swap(lockaddr, 1)) /* got the lock */
Run Code Online (Sandbox Code Playgroud)
和:
if (!atomic_compare_and_swap(lockaddr, 0, val)) /* got the lock */
Run Code Online (Sandbox Code Playgroud)
其中val
可能只是一个常量或锁定的新潜在所有者的标识符.
我想知道的是x86(和x86_64)机器上的两者之间是否存在任何显着的性能差异.我知道这是一个相当广泛的问题,因为单个cpu模型之间的答案可能差异很大,但这是我要求的原因之一,而不仅仅是我可以访问的几个cpus的基准测试.
如果mem
是共享内存位置,我是否需要:
XCHG EAX,mem
Run Code Online (Sandbox Code Playgroud)
要么:
LOCK XCHG EAX,mem
Run Code Online (Sandbox Code Playgroud)
原子地进行交换?
谷歌搜索这会产生是和否答案.有没有人知道这个?
我是新手使用gcc内联汇编,并且想知道在x86多核机器上是否可以实现自旋锁(没有竞争条件)(使用AT&T语法):
spin_lock: mov 0 eax lock cmpxchg 1 [lock_addr] jnz spin_lock ret spin_unlock: lock mov 0 [lock_addr] ret
我最近遇到了一些同步问题,这使我成为自旋锁和原子计数器.然后,我正在寻找多一点,这些工作是如何找到的std :: memory_order及记忆力障碍(mfence
,lfence
和sfence
).
所以现在,似乎我应该使用获取/释放螺旋锁并放松计数器.
x86 MFENCE - 内存围栏
x86 LOCK - 断言LOCK#信号
这三个操作(lock = test_and_set,unlock = clear,increment = operator ++ = fetch_add)的默认(seq_cst)内存顺序和获取/释放/放松的机器代码(编辑:见下文)是什么(按此顺序排列三个操作).有什么区别(哪些内存屏障在哪里)和成本(多少CPU周期)?
我只是想知道我的旧代码(没有指定内存顺序= seq_cst使用)真的是多么糟糕,如果我应该创建一些class atomic_counter
派生std::atomic
但使用轻松的内存排序 (以及在某些地方使用获取/释放而不是互斥锁的好螺旋锁. ..或者使用来自boost库的东西 - 到目前为止我已经避免了提升).
到目前为止,我确实理解自旋锁比自身保护更多(但也有一些共享资源/内存),因此,必须有一些东西可以使一些内存视图对于多个线程/内核(即获取/释放和内存围栏)保持一致).原子计数器只为自己而存在,只需要原子增量(不涉及其他内存,当我读它时我并不真正关心它的价值,它是信息性的,可以是几个循环旧,没问题).有一些LOCK
前缀和一些xchg …
昨天我张贴这个问题上如何写一个快速自旋锁.感谢Cory Nelson,我似乎找到了一个比我的问题中讨论的其他方法更优越的方法.我使用该CMPXCHG
指令来检查锁是否为0并因此是空闲的.CMPXCHG
在'BYTE'上运作,WORD
并且DWORD
.我会假设指令运行得更快BYTE
.但我写了一个实现每种数据类型的锁:
inline void spin_lock_8(char* lck)
{
__asm
{
mov ebx, lck ;move lck pointer into ebx
xor cl, cl ;set CL to 0
inc cl ;increment CL to 1
pause ;
spin_loop:
xor al, al ;set AL to 0
lock cmpxchg byte ptr [ebx], cl ;compare AL to CL. If equal ZF is set and CL is loaded into address pointed to by ebx
jnz spin_loop ;jump …
Run Code Online (Sandbox Code Playgroud) 好吧,我有一个关于线程的问题.
有两个未同步的线程同时运行并使用全局资源"int num"1st:
void Thread()
{
int i;
for ( i=0 ; i < 100000000; i++ )
{
num++;
num--;
}
}
Run Code Online (Sandbox Code Playgroud)
第二:
void Thread2()
{
int j;
for ( j=0 ; j < 100000000; j++ )
{
num++;
num--;
}
}
Run Code Online (Sandbox Code Playgroud)
问题陈述:程序结束时变量"num"的可能值是什么.现在我会说0将是程序结束时num的值,但是,尝试运行此代码,你会发现结果是随机的,我不明白为什么?
完整代码:
#include <windows.h>
#include <process.h>
#include <stdio.h>
int static num=0;
void Thread()
{
int i;
for ( i=0 ; i < 100000000; i++ )
{
num++;
num--;
}
}
void Thread2()
{
int j;
for ( j=0 …
Run Code Online (Sandbox Code Playgroud) 我假设简单的自旋锁不会进入操作系统等待这个问题的目的。
我发现简单的自旋锁通常使用lock xchg
orlock bts
代替 来实现lock cmpxchg
。
cmpxchg
但是如果期望不匹配,是否会避免写入该值?那么失败的尝试不是更便宜吗cmpxchg
?
或者即使cmpxchg
发生故障也会写入数据并使其他核心的缓存线无效?
这个问题类似于什么具体将 x86 缓存行标记为脏 - 任何写入,还是需要显式更改?,但它是特定的cmpxchg
,而不是普遍的。
我是低级别的新手,所以我完全忘记了你可能面临的问题,我甚至不确定我是否理解"原子"一词.现在我试图通过扩展程序集围绕内存操作进行简单的原子锁.为什么?为了好奇.我知道我在这里重新发明轮子,可能会过度简化整个过程.
这个问题? 我在这里提供的代码是否实现了使内存操作既线程安全又可重入的目标?
我只想做...
代码:
volatile int atomic_gate_memory = 0;
static inline void atomic_open(volatile int *gate)
{
asm volatile (
"wait:\n"
"cmp %[lock], %[gate]\n"
"je wait\n"
"mov %[lock], %[gate]\n"
: [gate] "=m" (*gate)
: [lock] "r" (1)
);
}
static inline void atomic_close(volatile int *gate)
{
asm volatile (
"mov %[lock], %[gate]\n"
: [gate] "=m" (*gate)
: [lock] "r" (0)
);
}
Run Code Online (Sandbox Code Playgroud)
然后像:
void *_malloc(size_t size)
{
atomic_open(&atomic_gate_memory);
void *mem = malloc(size);
atomic_close(&atomic_gate_memory); …
Run Code Online (Sandbox Code Playgroud) 我正在尝试在我的代码中实现一个自旋锁,但是我基于Wikipedia实现的自旋锁导致了极慢的性能.
int lockValue = 0;
void lock() {
__asm__("loop: \n\t"
"movl $1, %eax \n\t"
"xchg %eax, lockValue \n\t"
"test %eax, %eax \n\t"
"jnz loop");
}
Run Code Online (Sandbox Code Playgroud)
有没有办法改善这一点,使其更快?
谢谢.
在程序集中实现自旋锁.在这里,我发布了一个我提出的解决方案.这是对的吗?你知道一个较短的吗?
锁:
mov ecx, 0
.loop:
xchg [eax], ecx
cmp ecx, 0
je .loop
Run Code Online (Sandbox Code Playgroud)
发布:
lock dec dword [eax]
Run Code Online (Sandbox Code Playgroud)
eax初始化为-1(这意味着锁是免费的).这适用于许多线程(不一定是2).