观察以下用Java编写的程序(完整的runnable版本如下,但程序的重要部分在下面的代码片段中):
import java.util.ArrayList;
/** A not easy to explain benchmark.
*/
class MultiVolatileJavaExperiment {
public static void main(String[] args) {
(new MultiVolatileJavaExperiment()).mainMethod(args);
}
int size = Integer.parseInt(System.getProperty("size"));
int par = Integer.parseInt(System.getProperty("par"));
public void mainMethod(String[] args) {
int times = 0;
if (args.length == 0) times = 1;
else times = Integer.parseInt(args[0]);
ArrayList < Long > measurements = new ArrayList < Long > ();
for (int i = 0; i < times; i++) {
long start = System.currentTimeMillis();
run();
long end …Run Code Online (Sandbox Code Playgroud) 我正在用c ++编写多线程应用程序,其中性能至关重要.我需要在线程之间复制小结构时使用大量锁定,为此我选择使用自旋锁.
我已经做了一些研究和速度测试,我发现大多数实现大致同样快:
__asm {}使用类似这样的代码,它得分约70个时间单位,但我不确定是否已创建适当的内存屏障.编辑:这里给出的时间是2个线程锁定和解锁螺旋锁1,000,000次所需的时间.
我知道这并没有太大的区别,但是由于自旋锁是一个使用频繁的对象,人们会认为程序员会同意以最快的方式制作自旋锁.谷歌搜索导致许多不同的方法.我认为如果使用内联汇编并使用指令而不是比较32位寄存器来实现上述方法将是最快的CMPXCHG8B.此外,必须考虑内存障碍,这可以通过LOCK CMPXHG8B(我认为?)来完成,这保证了内核之间共享内存的"专有权".最后[有人建议]对于繁忙的等待应该伴随NOP:REP,这将使超线程处理器切换到另一个线程,但我不确定这是否是真的?
根据我对不同螺旋锁的性能测试,可以看出没有太大区别,但出于纯粹的学术目的,我想知道哪一个是最快的.但是由于我在汇编语言和内存障碍方面的经验非常有限,如果有人可以为我在LOCK CMPXCHG8B中提供的最后一个示例编写汇编代码并在以下模板中使用适当的内存屏障,我会很高兴:
__asm
{
spin_lock:
;locking code.
spin_unlock:
;unlocking code.
}
Run Code Online (Sandbox Code Playgroud) 我想知道的是lock xchg,mfence从一个线程访问内存位置的角度来看是否会有类似的行为,这个内存位置正在被其他线程进行变异(让我们随便说).它能保证我获得最新的价值吗?之后的内存读/写指令?
我混淆的原因是:
8.2.2"读取或写入不能通过I/O指令,锁定指令或序列化指令重新排序."
-Intel 64 Developers Manual Vol.3
这是否适用于线程?
mfence 状态:
对MFENCE指令之前发出的所有内存加载和存储到内存指令执行序列化操作.此序列化操作保证在MFENCE指令之前的任何加载或存储指令全局可见之前,在程序顺序之前的每条加载和存储指令都是全局可见的.MFENCE指令针对所有加载和存储指令,其他MFENCE指令,任何SFENCE和LFENCE指令以及任何序列化指令(例如CPUID指令)进行排序.
-Intel 64 Developers Manual Vol 3A
这听起来更有力.因为它听起来mfence几乎正在刷写写缓冲区,或者至少延伸到写缓冲区和其他内核以确保我未来的加载/存储是最新的.
当基准标记时,两个指令都需要约100个循环才能完成.所以我无论如何都看不出那么大的差异.
主要是我只是困惑.我的指令基于lock互斥体使用,但后来这些包含没有内存栅栏.然后,我看到锁免费使用内存栅栏编程,但没有锁.我知道AMD64有一个非常强大的内存模型,但过时的值可以在缓存中持续存在.如果lock行为与行为不同,mfence那么互斥量如何帮助您查看最新值?
x86 assembly multithreading cpu-architecture memory-barriers
我有一套xchg基于测试的装配锁.我的问题是:
使用指令时是否需要使用内存防护(mfence,sfence或lfence)xchg?
编辑:
64位平台:采用Intel nehalem
在Visual C++ 2013上,当我编译以下代码时
#include <atomic>
int main()
{
std::atomic<int> v(2);
return v.fetch_add(1, std::memory_order_relaxed);
}
Run Code Online (Sandbox Code Playgroud)
我在x86上找回了以下程序集:
51 push ecx
B8 02 00 00 00 mov eax,2
8D 0C 24 lea ecx,[esp]
87 01 xchg eax,dword ptr [ecx]
B8 01 00 00 00 mov eax,1
F0 0F C1 01 lock xadd dword ptr [ecx],eax
59 pop ecx
C3 ret
Run Code Online (Sandbox Code Playgroud)
在x64上类似:
B8 02 00 00 00 mov eax,2
87 44 24 08 xchg eax,dword ptr [rsp+8]
B8 01 00 00 00 mov eax,1 …Run Code Online (Sandbox Code Playgroud) assembly ×4
x86 ×4
c++ ×3
atomic ×1
c ×1
concurrency ×1
java ×1
jvm ×1
spinlock ×1
visual-c++ ×1