如果有两个线程访问全局变量,那么许多教程都说使变量volatile变为阻止编译器将变量缓存在寄存器中,从而无法正确更新.但是,访问共享变量的两个线程是通过互斥锁来调用保护的东西不是吗?但是在这种情况下,在线程锁定和释放互斥锁之间,代码处于一个关键部分,只有那个线程可以访问变量,在这种情况下变量不需要是volatile?
那么多线程程序中volatile的用途/目的是什么?
Linux内核lock; addl $0,0(%%esp)
用作写屏障,而RE2库xchgl (%0),%0
用作写屏障.有什么区别,哪个更好?
x86还需要读屏障指令吗?RE2将其读屏障功能定义为x86上的无操作,而Linux lfence
根据SSE2是否可用将其定义为无操作或无操作.什么时候lfence
需要?
Interlocked.Exchange和Volatile.Write有什么区别?
两种方法都更新某些变量的值.有人可以总结何时使用它们?
http://msdn.microsoft.com/ru-ru/library/bb337971 和http://msdn.microsoft.com/en-us/library/gg712713.aspx
特别是我需要更新我的数组的双项,我希望另一个线程看到最新的值.什么是首选?Interlocked.Exchange(ref arr[3], myValue)
或Volatile.Write(ref arr[3], info);
在那里arr
被声明为double
?
================================================== ==========================真实的例子,我声明了这样的双数组:
private double[] _cachedProduct;
Run Code Online (Sandbox Code Playgroud)
在一个线程中,我更新它:
_cachedProduct[instrumentId] = calcValue;
...
are.Set();
Run Code Online (Sandbox Code Playgroud)
在另一个线程中,我像这样读取这个数组:
while(true) {
are.WaitOne();
...
result += _cachedProduct[instrumentId];
...
}
Run Code Online (Sandbox Code Playgroud)
对我来说它只是工作正常.然而,为了确保"它将永远有效",无论它看起来我应该添加Volatile.Write
或Interlocked.Exchange
.因为双重更新不能保证是原子的http://msdn.microsoft.com/en-us/library/aa691278%28VS.71%29.aspx
在这个问题的答案中,我希望看到Volatile和Interlocked类的详细比较.为什么我们需要2节课?哪一个和何时使用?
如果mem
是共享内存位置,我是否需要:
XCHG EAX,mem
Run Code Online (Sandbox Code Playgroud)
要么:
LOCK XCHG EAX,mem
Run Code Online (Sandbox Code Playgroud)
原子地进行交换?
谷歌搜索这会产生是和否答案.有没有人知道这个?
我有一些不可变的数据结构,我想使用引用计数来管理,在SMP系统上的线程之间共享它们.
这是发布代码的样子:
void avocado_release(struct avocado *p)
{
if (atomic_dec(p->refcount) == 0) {
free(p->pit);
free(p->juicy_innards);
free(p);
}
}
Run Code Online (Sandbox Code Playgroud)
是否atomic_dec
需要在它的内存屏障?如果是这样,什么样的记忆障碍?
附加说明:应用程序必须在PowerPC和x86上运行,因此欢迎任何特定于处理器的信息.我已经知道GCC原子内置.至于不变性,refcount是唯一在对象持续时间内发生变化的字段.
在C++和2012之后:Herb Sutter - 原子<>武器, Herb Sutter中的2个(约0:38:20)认为应该使用xchg
,而不是mov
/ 在x86 mfence
上实现atomic_store
.他似乎也暗示这个特定的指令序列是每个人都同意的.但是,海湾合作委员会使用后者.为什么GCC使用这个特定的实现?
我有一套xchg
基于测试的装配锁.我的问题是:
使用指令时是否需要使用内存防护(mfence
,sfence
或lfence
)xchg
?
编辑:
64位平台:采用Intel nehalem
我已经看到这个答案和这个答案,但也显得清晰和明确有关的等价或不等价mfence
和xchg
没有非时间指示的假设下.
英特尔指令参考对于xchg
提到这个指令是用于实现信号量或进程同步相似的数据结构有用,和其它参考文献的第8章卷3A.该参考文献陈述如下.
对于P6系列处理器,锁定操作会序列化所有未完成的加载和存储操作(即等待它们完成).对于奔腾4和英特尔至强处理器,此规则也是如此,但有一个例外.引用弱有序内存类型(例如WC内存类型)的加载操作可能无法序列化.
该mfence
文件声称如下.
对MFENCE指令之前发出的所有内存加载和存储到内存指令执行序列化操作.此序列化操作保证在遵循MFENCE指令的任何加载或存储指令之前,按程序顺序在MFENCE指令之前的每个加载和存储指令都变为全局可见.1 MFENCE指令针对所有加载和存储指令,其他MFENCE指令,任何LFENCE和SFENCE指令以及任何序列化指令(例如CPUID指令)进行排序.MFENCE不会序列化指令流.
如果我们忽略弱有序的内存类型,xchg(暗示lock
)是否包含了关于内存排序的所有mfence保证?
我已经阅读了很多关于内存排序的文章,并且所有这些文章都只说CPU重新加载和存储.
CPU(我对x86 CPU特别感兴趣)是否仅重新排序加载和存储,并且不重新排序它具有的其余指令?
正如我们从之前的回答中所知道的,它是否在处理器x86/x86_64中指示LFENCE?我们不能使用SFENCE
而不是MFENCE
顺序一致性.
这里的答案表明MFENCE
= SFENCE
+ LFENCE
,即LFENCE
没有我们不能提供顺序一致性的东西.
LFENCE
无法重新排序:
SFENCE
LFENCE
MOV reg, [addr]
Run Code Online (Sandbox Code Playgroud)
- 到 - >
MOV reg, [addr]
SFENCE
LFENCE
Run Code Online (Sandbox Code Playgroud)
例如重新排序MOV [addr], reg
LFENCE
- > LFENCE
MOV [addr], reg
由机制提供- 存储缓冲区,它重新排序存储 - 负载以提高性能,并且因为LFENCE
它不会阻止它.并SFENCE
禁用此机制.
什么机制禁用LFENCE
无法重新排序(x86没有机制 - Invalidate-Queue)?
并且只是在理论上或者在现实中重新排序SFENCE
MOV reg, [addr]
- > MOV reg, [addr]
SFENCE
可能吗?如果可能,实际上,什么机制,它是如何工作的?