问题标签 [memory-fences]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
1 回答
2051 浏览

c - 编译器级别和硬件级别的内存防护

我在这里读到了关于内存围栏的信息......我需要对此进行一些澄清

asm volatile ("" : : : "内存")

这提供了编译器级别的内存栅栏,并且处理器在使用它时仍然可以进行重新排序。

无论如何,我可以使用类似的指令同时实现编译器级别的防护和处理器级别的防护吗?

我碰到,

asm volatile("sfence" : : : "memory")

这是做什么的?它是否仅提供编译器级别的存储防护?

对此的任何输入都将非常有帮助。

谢谢

0 投票
3 回答
741 浏览

java - jni/java:线程安全发布/共享有效的不可变本机对象

1)我有一个本地java函数,它传递几个参数,它的实现是一个本地C++构造函数来创建一个对象并返回一个从指针到对象的long。该对象的构造成员实际上是不可变的。然后,C++ 对象可以根据其构造状态进行工作。

2) 获取函数调用结果的 java 代码在某处安全地发布指针的加长版本(没有互斥体)并更改 volatile 变量以希望将本机 C++ 对象中的内存更改发布到其他线程

现在另一个线程读取 2) 的 volatile 变量,然后获取已发布的 long,并调用另一个本机函数,该函数访问 C++ 内存空间中的有效不可变对象以完成一些工作。

问题:由于 Java 内存模型对 volatile 和栅栏的保证,是否保证其他线程可以看到完全构造的本机对象?我敢打赌,在某些平台上答案是肯定的,但我看到不同的芯片使用栅栏以不同的方式工作,并且想知道所有可以使用 java 的平台。

0 投票
2 回答
288 浏览

java - 对象构造完成后,是否与其他线程建立了内存栅栏?

有人可以验证我对构造函数执行后建立的内存围栏的理解。例如,假设我有一个名为 Stock 的类。

此外,假设构造函数由 Thread1 执行updateQty()然后由Thread2updatePrice()调用多次(始终由 Thread2 调用)。

我的论点是,在 Thread1 创建对象之后,对象的“可见性”与 jvm 中的所有其他线程建立起来。而且由于这两个可变变量仅由 Thread2 更改,因此我不需要任何锁定。我对么?

0 投票
2 回答
1594 浏览

c++ - 内存屏障:如何确保工作线程看到初始化写入?

我对使用内存屏障/围栏进行编程相当陌生,我想知道我们如何保证设置写入在随后在其他 CPU 上运行的工作函数中可见。例如,考虑以下情况:

之后(不是同时)运行很多次:

在 CPU 2 上,如果mySetup为 1,sheep则保证为 9——但我们如何保证它mySetup不是 0?

到目前为止,我能想到的只是在 CPU 2 上旋转等待直到setup1。但这似乎很丑陋,因为旋转等待只需要等待第一次ManipulateSheep()被调用。肯定有更好的方法吗?

请注意,未初始化代码还有一个对称问题:假设您正在编写一个无锁数据结构,该结构在其生命周期内分配内存。在析构函数中(假设所有线程都已完成调用方法),您想要释放所有内存,这意味着您需要运行析构函数的 CPU 具有最新的变量值。在这种情况下甚至不可能旋转等待,因为析构函数无法知道“最新”状态是什么来检查它。

编辑:我想我要问的是:有没有办法说“等待我的所有商店传播到其他 CPU”(用于初始化)和“等待所有商店传播到我的 CPU”(用于未初始化)?

0 投票
5 回答
9458 浏览

c++ - 使用显式栅栏和 std::atomic 有什么区别?

假设对齐的指针加载和存储在目标平台上自然是原子的,这有什么区别:

这:

还有这个:

我的印象是它们都是等价的,但是Relacy在第一种情况下检测到数据竞争(仅):

我联系了 Relacy 的作者,以了解这是否是预期的行为;他说我的测试用例中确实存在数据竞争。但是,我很难发现它;有人可以向我指出比赛是什么吗?最重要的是,这三种情况有什么区别?

更新:我想到 Relacy 可能只是在抱怨跨线程访问的变量的原子性(或者说缺乏原子性)......毕竟,它不知道我打算只在平台上使用此代码其中对齐的整数/指针访问自然是原子的。

另一个更新:Jeff Preshing 写了一篇优秀的博客文章,解释了显式栅栏和内置栅栏(“栅栏”与“操作”)之间的区别。案例 2 和 3 显然不等价!(无论如何,在某些微妙的情况下。)

0 投票
1 回答
416 浏览

assembly - 这个 MMX 内存复制代码需要栅栏吗?

这个基本的 mmx 内存复制代码在释放模式下会破坏内存,但仅限于某些编译器。具体来说是 Visual Studio 2010。我认为这是因为这段代码需要一个内存围栏,但我不确定它会去哪里或确切原因。此代码与 Visual Studio 2005 完美配合。

MMXMemCopy ENDP

0 投票
1 回答
394 浏览

c++ - 使用 QAtomicInt 作为内存围栏

再说一次关于无锁的事情......

假设我实现了一个简单的基于数组的整数循环 FIFO。FIFO 由 2 个线程单生产者、单消费者访问。读取和写入索引始终在访问项目后更新。在单个 CPU 上,这将是安全的(假设索引的更新操作是原子的),因为只有一个线程具有对索引的写访问权限。在 SMP 机器上,这可能会导致问题,因为两个 CPU 可能会由于其缓存和重新排序而看到不同的索引表示。

QT 具有跨平台原子变量,它们也实现了内存栅栏,使用 QAtomicInt 会使 fifo 实现 SMP 安全还是我忽略了什么?

0 投票
3 回答
1059 浏览

c++ - 原子递减比递增更昂贵吗?

Herb Sutter在他的博客中写道

[...] 因为增加智能指针引用计数 通常可以优化为与优化shared_ptr实现中的普通增量相同——在生成的代码中只是一条普通的增量指令,没有栅栏。

但是,减量必须是原子减量或等效物,它会生成特殊的处理器内存指令,这些指令本身更昂贵,并且在此之上会导致内存栅栏限制优化周围代码。

文本是关于实施的shared_ptr,我不确定他的评论是否仅适用于此或一般情况下。从他的表述中,我推测它是一般的。

但是当我想到它时,我只能在if(counter==0)紧随其后想到“更昂贵的减量”——这可能是shared_ptr.

因此,我想知道原子操作++counter是否(通常)总是比快--counter还是仅仅因为if(--counter==0)...shared_ptr?

0 投票
1 回答
650 浏览

multithreading - C++11 何时使用内存栅栏?

我正在编写一些线程化的 C++11 代码,但我不确定何时需要使用内存围栏或其他东西。所以这基本上就是我正在做的事情:

我想知道,我需要采取哪些步骤来确保在另一个线程上运行的 Work() 函数中可以安全地访问 args。写在构造函数中,然后在单独的函数中创建线程就够了吗?或者我是否需要一个内存栅栏,我如何制作一个内存栅栏以确保所有 3 个 args 都由主线程写入,然后由 Worker 线程读取?

谢谢你的帮助!

0 投票
2 回答
586 浏览

multithreading - 互斥体、原子和栅栏:什么提供了最好的权衡和可移植性?C++11

我试图更深入地了解在 C++ 11 中编写多线程应用程序时我有多少选项。

简而言之,到目前为止我看到了这 3 个选项:

  • 具有显式锁定和释放机制的互斥体,它们通过锁定和释放来保持线程同步,这很昂贵并且不能保证我的代码执行的顺序,但通常这种解决方案在不同的内存模型之间是非常可移植的。
  • 原子操作,由于 atomic = 1single operation without a race 并且始终是一致的,sync 是在不加锁和释放的情况下完成的,没有race 就不需要加锁,具有高度优化的原子操作,但是 atomics 仍然不能保证我的代码将执行的顺序。
  • 栅栏,它们在我的代码中创建了一个块,编译器无法重新排序任何内容,灵活性较低,并且它们在代码维护方面往往成本高昂,因为我总是必须关注真正正在执行的内容以及按什么顺序,但它们也改进了缓存技术,在这 3 种解决方案中,它们可能是行为最可预测的一种。

这或多或少是我从关于线程和内存模型的第一堂课中学到的核心,我的问题是:

我打算使用无锁数据结构和原子来实现灵活性和良好的性能,这里的问题是,显然 X86 机器执行的内存重新排序与 ARM 机器不同,我希望尽可能地保持我的代码可移植至少在这两个平台上,那么当两个平台不能保证具有相同的重新排序机制时,你可以建议什么样的方法来编写一个可移植的多线程软件?或者原子操作是最好的选择,因为它现在是我错了?

例如,我注意到英特尔 TBB 库(不是 C++11 代码)正在移植到 ARM/Android,并对专用于原子的部分进行了大量修改,所以也许我可以用 C+ 编写可移植的多线程代码+11,使用无锁数据结构,并在稍后将我的库移植到另一个平台时优化有关原子的部分?