Questions tagged «memory-barriers»

4
函数是否是现代平台的有效内存屏障?
在我审阅的代码库中,我发现了以下成语。 void notify(struct actor_t act) { write(act.pipe, "M", 1); } // thread A sending data to thread B void send(byte *data) { global.data = data; notify(threadB); } // in thread B event loop read(this.sock, &cmd, 1); switch (cmd) { case 'M': use_data(global.data);break; ... } 我对我的团队的资深成员对作者说:“保存”,这里没有内存屏障!您不保证global.data将其从缓存刷新到主内存。如果线程A和线程B将在其中运行两个不同的处理器-此方案可能会失败”。 高级程序员咧嘴笑着,慢慢地解释,好像在解释他的五岁男孩如何系鞋带:“听小男孩,在高负载测试和实际客户中,我们在这里看到了许多与线程相关的错误”,他停下来挠挠他长长的胡须,“但是这个习语从来没有犯过错误”。 “但是,它在书中说……” “安静!”他迅速向我嘘声,“也许从理论上讲不能保证,但实际上,您使用函数调用的事实实际上是内存障碍。编译器不会对指令进行重新排序global.data = data,因为它不知道是否任何在函数调用中使用它的人,x86架构将确保在线程B从管道读取命令时其他CPU将看到此全局数据,请放心,我们有很多现实问题需要担心。我们不需要在虚假的理论问题上投入额外的精力。 …

1
Java中的内存防护有什么用?
在尝试了解如何实现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障碍不是必需的。 大多数内存屏障也具有同步效果。这些特别取决于其他线程中使用的屏障类型和先前执行的屏障指令。由于障碍指令的全部含义是特定于硬件的,因此我将坚持使用更高级别的(C ++)障碍。在C ++中,例如,改变由之前的释放屏障指令是执行一个线程可见获取屏障指令。 我的假设正确吗?如果是这样,我的问题是: 可用的内存屏障是否VarHandle会引起任何类型的内存同步? 无论它们是否引起内存同步,重新排序约束在Java中可能有什么用?Java内存模型已经就可变字段,锁或VarHandle类似操作的顺序提供了一些非常有力的保证#compareAndSet。 如果您正在寻找一个示例:前面提到BufferedSubscription的SubmissionPublisher(内部链接为的内部类)在第1079行中建立了完整的围栏(功能growAndAdd;由于链接的网站不支持片段标识符,因此仅需使用CTRL + F )。但是,我不清楚它的用途。

4
如何在C ++ 11中实现StoreLoad障碍?
我想编写可移植的代码(Intel,ARM,PowerPC ...)来解决经典问题的变体: Initially: X=Y=0 Thread A: X=1 if(!Y){ do something } Thread B: Y=1 if(!X){ do something } 其中的目的是为了避免在这两个线程都在做的情况something。(如果两者都不运行,这很好;这不是一次运行的机制。)如果您在下面的推理中发现一些缺陷,请更正我。 我知道,我可以通过memory_order_seq_cst原子stores和loads 实现目标,如下所示: std::atomic<int> x{0},y{0}; void thread_a(){ x.store(1); if(!y.load()) foo(); } void thread_b(){ y.store(1); if(!x.load()) bar(); } 之所以能够达到目标,是因为 {x.store(1), y.store(1), y.load(), x.load()}事件上必须有一些总订单,并且必须与程序订单的“优势”相符: x.store(1) “在TO之前” y.load() y.store(1) “在TO之前” x.load() 如果foo()被调用,那么我们还有其他优势: y.load() “先读值” y.store(1) …

1
C11原子获取/发布和x86_64缺乏加载/存储一致性?
我在C11标准的5.1.2.4节中苦苦挣扎,尤其是Release / Acquire的语义。我注意到https://preshing.com/20120913/acquire-and-release-semantics/(以及其他)指出: ...释放语义可防止以程序顺序在写释放之前进行任何读或写操作,从而对写释放进行内存重新排序。 因此,对于以下情况: typedef struct test_struct { _Atomic(bool) ready ; int v1 ; int v2 ; } test_struct_t ; extern void test_init(test_struct_t* ts, int v1, int v2) { ts->v1 = v1 ; ts->v2 = v2 ; atomic_store_explicit(&ts->ready, false, memory_order_release) ; } extern int test_thread_1(test_struct_t* ts, int v2) { …
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.