我试着寻找这方面的细节,我甚至阅读了关于互斥和原子的标准......但我仍然无法理解C++ 11内存模型的可见性保证.据我所知,互斥BESIDE互斥的一个非常重要的特点是确保可见性.Aka每次只有一个线程增加计数器是不够的,重要的是线程增加了最后使用互斥锁的线程所存储的计数器(我真的不知道为什么人们在讨论时不再提这个互斥,也许我有坏老师:)).所以从我可以告诉原子并不强制立即可见性:(来自维护boost :: thread并已实现c ++ 11线程和互斥库的人):
具有memory_order_seq_cst的fence不会强制立即查看其他线程(并且MFENCE指令也不会).C++ 0x内存排序约束只是---排序约束.memory_order_seq_cst操作形成一个总顺序,但对该顺序没有任何限制,除了它必须由所有线程达成一致,并且它不得违反其他排序约束.特别是,如果线程按照与约束一致的顺序看到值,则线程可能会在一段时间内继续看到"陈旧"值.
而且我很好.但问题在于我无法理解C++ 11关于原子的构造是"全局的",而且只能确保原子变量的一致性.特别是我了解以下内存排序中的哪些(如果有的话)保证在加载和存储之前和之后将有一个内存栅栏:http: //www.stdthread.co.uk/doc/headers/atomic/memory_order. HTML
从我可以告诉std :: memory_order_seq_cst插入mem屏障,而其他只强制执行某些内存位置上的操作的顺序.
所以有人可以清楚这一点,我认为很多人会使用std :: atomic制作可怕的错误,如果他们不使用默认值(例如std :: memory_order_seq_cst内存排序),
那么就是2.如果我是对的,那就意味着第二行是此代码中的冗余:
atomicVar.store(42);
std::atomic_thread_fence(std::memory_order_seq_cst);
Run Code Online (Sandbox Code Playgroud)
3. std :: atomic_thread_fences在某种意义上与互斥量具有相同的要求,为了确保非原子变量的seq一致性,必须执行std :: atomic_thread_fence(std :: memory_order_seq_cst); 在load和std :: atomic_thread_fence(std :: memory_order_seq_cst)之前;
经过商店?
是的
{
regularSum+=atomicVar.load();
regularVar1++;
regularVar2++;
}
//...
{
regularVar1++;
regularVar2++;
atomicVar.store(74656);
}
Run Code Online (Sandbox Code Playgroud)
相当于
std::mutex mtx;
{
std::unique_lock<std::mutex> ul(mtx);
sum+=nowRegularVar;
regularVar++;
regularVar2++;
}
//..
{
std::unique_lock<std::mutex> ul(mtx);
regularVar1++;
regularVar2++;
nowRegularVar=(74656);
}
Run Code Online (Sandbox Code Playgroud)
我想不是,但我想确定.
编辑:5.可以断言?
只存在两个线程.
atomic<int*> p=nullptr;
Run Code Online (Sandbox Code Playgroud)
第一个线程写
{
nonatomic_p=(int*) malloc(16*1024*sizeof(int));
for(int i=0;i<16*1024;++i) …Run Code Online (Sandbox Code Playgroud) 内存障碍保证数据缓存一致.但是,它是否保证TLB一致?
我看到一个问题,当在线程之间传递MappedByteBuffer时,JVM(java 7更新1)有时会因内存错误(SIGBUS,SIGSEG)而崩溃.
例如
final AtomicReference<MappedByteBuffer> mbbQueue = new AtomicReference<>();
// in a background thread.
MappedByteBuffer map = raf.map(MapMode.READ_WRITE, offset, allocationSize);
Thread.yield();
while (!inQueue.compareAndSet(null, map));
// the main thread. (more than 10x faster than using map() in the same thread)
MappedByteBuffer mbb = inQueue.getAndSet(null);
Run Code Online (Sandbox Code Playgroud)
没有Thread.yield()我偶尔会在force(),put()和C的memcpy()中崩溃,这些都表示我试图非法访问内存.使用Thread.yield()我没有遇到任何问题,但这听起来不是一个可靠的解决方案.
有人遇到过这个问题吗?有关TLB和内存障碍的保证吗?
编辑:操作系统是Centos 5.7,我已经看到了i7和双Xeon机器上的行为.
为什么我这样做?因为写入消息的平均时间是35-100 ns,具体取决于长度,使用普通的write()并不是那么快.如果我在当前线程中进行内存映射和清理,则需要50-130微秒,使用后台线程执行此操作需要大约3-5微秒的主线程交换缓冲区.为什么我需要交换缓冲区呢?因为我写的是很多GB数据而且ByteBuffer的大小不能超过2 GB.
谈到这一点,我是新手.任何人都可以提供以下内存障碍之间差异的简化解释吗?
MemoryBarrier();_mm_mfence();asm volatile ("" : : : "memory");_ReadWriteBarrier();如果没有一个简单的解释,一些链接到好文章或书籍可能会帮助我顺利完成.到目前为止,我只是使用其他包装这些调用所写的对象,但我希望能够比我目前的想法有更好的理解,这基本上就是有不止一种方法来实现内存障碍.
阅读Joseph Albahari的线程教程,以下内容被提及为内存障碍的生成器:
lock陈述(Monitor.Enter/ Monitor.Exit)Interlocked班上的所有方法此外,Hans Passant和Brian Gideon 补充了以下内容(假设其中没有一个已经符合以前的类别之一):
Thread.Sleep()我想知道这个清单是否完整(如果完整清单甚至可以实际制作)
编辑补充建议:
我正在用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) Linux内核lock; addl $0,0(%%esp)用作写屏障,而RE2库xchgl (%0),%0用作写屏障.有什么区别,哪个更好?
x86还需要读屏障指令吗?RE2将其读屏障功能定义为x86上的无操作,而Linux lfence根据SSE2是否可用将其定义为无操作或无操作.什么时候lfence需要?
据我所知,mfence硬件内存屏障asm volatile ("" : : : "memory")是一个编译器障碍.但是,可以asm volatile ("" : : : "memory")用来代替mfence.
我迷惑的原因是这个链接
考虑以下spin_lock()实现,最初来自这个答案:
void spin_lock(volatile bool* lock) {
for (;;) {
// inserts an acquire memory barrier and a compiler barrier
if (!__atomic_test_and_set(lock, __ATOMIC_ACQUIRE))
return;
while (*lock) // no barriers; is it OK?
cpu_relax();
}
}
Run Code Online (Sandbox Code Playgroud)
我所知道的:
volatile防止编译器*lock在while循环的每次迭代中优化重新读取;volatile 不插入内存或编译器障碍 ;x86(例如在Linux内核中)和其他一些架构;spin_lock()执行针对通用体系结构; 这个例子插入它们__atomic_test_and_set().问题:
volatile这里是否足够或者是否存在while循环中需要内存或编译器障碍或原子操作的架构或编译器?
1.1根据C++标准?
1.2在实践中,对于已知的体系结构和编译器,特别是它支持的GCC和平台?
while根据C++11它的内存模型,循环是否安全?有几个相关的问题,但我无法从它们构建一个明确和明确的答案:
原则上:是的,如果程序执行从一个核心移动到下一个核心,则可能看不到在先前核心上发生的所有写入. …
在试图了解SubmissionPublisher(Java SE 10 中的源代码,OpenJDK | docs),在版本 9 中添加到 Java SE 的新类是如何实现的,我偶然发现了一些VarHandle我以前不知道的API 调用:
fullFence,acquireFence,releaseFence,loadLoadFence和storeStoreFence。
在做了一些研究之后,特别是关于内存屏障/栅栏的概念(我以前听说过它们,是的;但从未使用过它们,因此对它们的语义非常不熟悉),我想我对它们的用途有了基本的了解. 尽管如此,由于我的问题可能源于误解,我想确保我首先做对了:
内存屏障是关于读写操作的重新排序约束。
内存屏障可以分为两大类:单向和双向内存屏障,这取决于它们是否对读取或写入或两者都设置了约束。
C++ 支持多种内存屏障,但是,这些与VarHandle. 然而,一些在可用内存壁垒VarHandle提供排序的影响是兼容其相应的C ++内存屏障。
#fullFence 兼容 atomic_thread_fence(memory_order_seq_cst)#acquireFence 兼容 atomic_thread_fence(memory_order_acquire)#releaseFence 兼容 atomic_thread_fence(memory_order_release) #loadLoadFence并且#storeStoreFence没有兼容的 C++ 计数器部分兼容这个词在这里似乎非常重要,因为在细节方面语义明显不同。例如,所有 C++ 屏障都是双向的,而 Java 的屏障不是(必然)。
我的假设正确吗?如果是这样,我产生的问题是:
可用的内存屏障是否VarHandle会导致任何类型的内存同步? …
java concurrency memory-model java-memory-model memory-barriers
我正在学习不同的记忆顺序。
\n我有这段代码,它可以工作并通过 GCC 和 Clang 的线程清理程序:
\n#include <atomic>\n#include <iostream>\n#include <future>\n \nint state = 0;\nstd::atomic_int a = 0;\n\nvoid foo(int from, int to) \n{\n for (int i = 0; i < 10; i++)\n {\n while (a.load(std::memory_order_acquire) != from) {}\n state++;\n a.store(to, std::memory_order_release);\n }\n}\n\nint main()\n{ \n auto x = std::async(std::launch::async, foo, 0, 1);\n auto y = std::async(std::launch::async, foo, 1, 0);\n}\nRun Code Online (Sandbox Code Playgroud)\n我认为如果它最终没有返回,则“获取”加载是不必要的from,那么“获取”负载是不必要的,因此我决定使用“宽松”负载,然后使用“获取”栅栏。
我期望它能工作,但它被线程清理程序拒绝了,线程清理程序声称并发state++是数据竞争。
#include <atomic>\n#include <iostream>\n#include <future>\n \nint state = 0;\nstd::atomic_int …Run Code Online (Sandbox Code Playgroud) memory-barriers ×10
c++ ×5
x86 ×3
assembly ×2
atomic ×2
gcc ×2
java ×2
spinlock ×2
c# ×1
c++11 ×1
centos ×1
concurrency ×1
memory-model ×1
mutex ×1
stdatomic ×1
tlb ×1
visual-c++ ×1
windows ×1