精华内容
下载资源
问答
  • 2020-03-29 09:09:07

    内存栅栏(Memory Barrier)就是从本地或工作内存主存之间的拷贝动作

    必须保证 写操作线程先跨越内存栅栏,读线程后跨越内存栅栏,这样写操作线程所做的变更才对其他线程可见。synchronized和volatile都强制规定了所有的变更必须全局可见,该特性有助于跨越内存边界动作的发生。

    在程序运行过程中,所有的变更会先在寄存器或本地cache中完成,然后才会被拷贝到主存以跨越内存栅栏。这种跨越序列或顺序称为happens-before。

    写操作必须要happens-before读操作。

    更多相关内容
  • 本篇文章对内存栅栏与volatile关键字的使用进行了详细的分析介绍,需要的朋友参考下
  • Linux内存栅栏概述

    2018-05-10 15:40:19
    Linux内存栅栏概述 Linux内存栅栏概述 Linux内存栅栏概述
  • 理解内存栅栏

    千次阅读 2018-09-13 15:26:03
    http://book.51cto.com/art/201306/397838.htm 了解可见性:理解内存栅栏《Java虚拟机并发编程》第1章并发的威力与风险,在本章中,我们将...本节为大家介绍可见性:理解内存栅栏。1.3.3 了解可见性:理解内存栅栏...

    http://book.51cto.com/art/201306/397838.htm

     了解可见性:理解内存栅栏



    《Java虚拟机并发编程》第1章并发的威力与风险,在本章中,我们将快速回顾一下并发编程技术的来龙去脉,并讨论在实践过程中可能遇到的一些风险。在本章末尾,我们将简单展望一下本书后面将会介绍的那些令人兴奋的并发编程技术。本节为大家介绍可见性:理解内存栅栏。


    1.3.3 了解可见性:理解内存栅栏

    上面那个示例存在的问题是,主线程对其字段done所做的变更对新创建出来的线程不可见。造成这种现象的首要原因是,JIT编译器可能对新线程代码里的while循环进行了优化,并因此导致新线程在线程上下文中无法看到变量done的变化。此外,新线程可能会只从其寄存器或本地cache中读取标记变量done的值,而不是每次都跑去速度更慢的内存里进行操作。基于上述原因,新线程就无法看到主线程对其标记变量值的变更了,详情请参阅下文“什么是内存栅栏”。

    如果想要快速修复此问题,只需要将变量done标记为volatile就可以了。具体做法是将

    改为:

    关键字volatile的作用是告知JIT编译器不要对被标记变量执行任何可能影响其访问顺序的优化。该关键字警告JIT编译器,该变量可能会被某个线程更改,所以任何对该变量的读写访问都需要忽略本地cache并直接对内存进行操作。之前我将这个改动称为快速修复,是因为如果我们将所有变量都标记为volatile的话,虽然可以完全规避此类问题,但却会使每次变量访问都要跨越内存栅栏并最终导致程序性能下降。此外,在多个字段被多个线程并发访问的场景下,由于针对每个volatile字段的访问都是各自独立处理的,并且也无法将这些访问统一协调成一次访问,所以volatile关键字无法保证整体操作的原子性。该问题所造成的后果是,线程很可能对某些字段只能看到其中间结果,而对另一些变量则看到的是最终的变更结果。

    为了解决这个问题,我们可以屏蔽对变量的直接访问,并将所有访问都引导为通过同步的getter和setter函数来进行,具体代码如下所示:

    关键字synchronized在这里起到了至关重要的作用。由于synchronized是为数不多的几个可以令线程在进入和离开同步区块时都跨越内存栅栏的原语之一,所以如果多个线程在相同的实例对象上进行同步并且先申请到对象锁的线程完成了对实例对象的操作,则后面申请到对象锁的线程将肯定可以看到前面完成操作的线程所做的变更。再次提醒,要了解该问题的详情请参阅下文“什么是内存栅栏”。

    Joe问:什么是内存栅栏?

    简单来说,内存栅栏(Memory Barrier)就是从本地或工作内存到主存之间的拷贝动作。

    仅当写操作线程先跨越内存栅栏(参见附录2中Doug Lea所著《The JSR-133 Cookbook for Compiler Writers》)而读线程后跨越内存栅栏的情况下,写操作线程所做的变更才对其他线程可见。关键字synchronized和volatile都强制规定了所有的变更必须全局可见,该特性有助于跨越内存边界动作的发生,无论是有意为之还是无心插柳。

    在程序运行过程中,所有的变更会先在寄存器或本地cache中完成,然后才会被拷贝到主存以跨越内存栅栏。此种跨越序列或顺序称为happens-before,详情请参阅附录2中的“Java内存模型”以及Brian Goetz的著作《Java Concurrency in Practice》[Goe06]。

    写操作必须要happens-before读操作,即写线程需要在所有读线程跨越内存栅栏之前完成自己的跨越动作,其所做的变更才能对其他线程可见。

    Java并发API中很多操作都隐含有跨越内存栅栏的含义:volatile、synchronized、Thread中的函数如start()和interrupt()、ExecutorService中的函数以及像CountDownLatch这样的同步工具类等。

    展开全文
  • 内存栅栏与乱序执行

    2020-10-27 23:17:12
    1、内存栅栏 2、乱序执行(out-of-order execution) 1、内存栅栏 也称内存屏障,内存栅障,屏障指令等, 是一类同步屏障指令,是CPU或编译器在对内存随机访问的操作中的一个同步点,使得此点之前的所有读写操作...

    目录

    1、内存栅栏

    2、乱序执行(out-of-order execution)


    1、内存栅栏

    也称内存屏障,内存栅障,屏障指令等, 是一类同步屏障指令,是CPU或编译器在对内存随机访问的操作中的一个同步点,使得此点之前的所有读写操作都执行后才可以开始执行此点之后的操作

    语义上,内存屏障之前的所有写操作都要写入内存;内存屏障之后的读操作都可以获得同步屏障之前的写操作的结果。因此,对于敏感的程序块,写操作之后、读操作之前可以插入内存屏障。

    大多数处理器提供了内存屏障指令:

    • 完全内存屏障(full memory barrier)保障了早于屏障的内存读写操作的结果提交到内存之后,再执行晚于屏障的读写操作。

    • 内存读屏障(read memory barrier)仅确保了内存读操作;

    • 内存写屏障(write memory barrier)仅保证了内存写操作。

    2、乱序执行(out-of-order execution)

    指CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理的技术。比方Core乱序执行引擎说程序某一段有7条指令,此时CPU将根据各单元电路的空闲状态和各指令能否提前执行的具体情况分析后,将能提前执行的指令立即发送给相应电路执行。

    在按序执行中,一旦遇到指令依赖的情况,流水线就会停滞,如果采用乱序执行,就可以跳到下一个非依赖指令并发布它。这样,执行单元就可以总是处于工作状态,把时间浪费减到最少。乱序执行可以允许在发布指令3前发布指令4~8,而且这些指令的执行结果可以在指令3引出后立即引出(按序引出对X86 CPU来说是必需的),实际解码率又会增加25%。不过PⅡ和K6从乱序执行中得到的好处有限,因为如果CPU遇到指令依赖情况,它必须找到更多的非依赖指令进行发布。

    展开全文
  • 因为这类操作就像画了一条任何代码都无法跨越的线一样, 所以栅栏操作通常也被称为“内存栅栏”(memory barriers)。 二、内存栅栏使用思想 使用栅栏的一般想法是: 当一个获取操作能看到释放栅栏操作后的存储结果,...

    一、栅栏定义

    栅栏操作会对内存序列进行约束,使其无法对任何数据进行修改, 典型的做法是与使用memory_order_relaxed约束序的原子操作一起使用。 栅栏属于全局操作, 执行栅栏操作可以影响到在线程中的其他原子操作。 因为这类操作就像画了一条任何代码都无法跨越的线一样, 所以栅栏操作通常也被称为“内存栅栏”(memory barriers)。

    二、内存栅栏使用思想

    使用栅栏的一般想法是:
    当一个获取操作能看到释放栅栏操作后的存储结果, 那么这个栅栏就与获取操作同步;并且, 当加载操作在获取栅栏操作前, 看到一个释放操作的结果, 那么这个释放操作同步于获取栅栏。
    举一个简单的例子, 当一个加载操作在获取栅栏前, 看到一个值有存储操作写入, 且这个存储操作发生在释放栅栏后, 那么释放栅栏与获取栅栏是同步的。
    虽然, 栅栏同步依赖于读取/写入的操作发生于栅栏之前/后, 但是这里有一点很重要: 同步点, 就是栅栏本身。

    三、内存栅栏的应用

    1. 内存栅栏可以让自由操作变的有序

    #include <atomic>
    #include <thread>
    #include <assert.h>
    
    std::atomic<bool> x,y;
    std::atomic<int> z;
    
    void write_x_then_y()
    {
        x.store(true,std::memory_order_relaxed);//1
        std::atomic_thread_fence(std::memory_order_release);//2
        y.store(true,std::memory_order_relaxed);//3
    }
    
    void read_y_then_x()
    {
        while(!y.load(std::memory_order_relaxed));//4
        std::atomic_thread_fence(std::memory_order_acquire);//5
        if(x.load(std::memory_order_relaxed))//6
            ++z;
    }
    
    int main()
    {
        x=false;
        y=false;
        z=0;
        std::thread a(write_x_then_y);
        std::thread b(read_y_then_x);
        a.join();
        b.join();
        assert(z.load()!=0);//7
    }
    

    释放栅栏②与获取栅栏⑤同步, 这是因为加载y的操作④读取的是在③处存储的值。 所以, 在
    ①处存储x先行与⑥处加载x, 最后x读取出来必为true, 并且断言不会被触发⑦。 原先不带栅栏
    的存储和加载x都是无序的, 并且断言是可能会触发的。 需要注意的是, 这两个栅栏都是必要
    的: 你需要在一个线程中进行释放, 然后在另一个线程中进行获取, 这样才能构建出同步关
    系。
    在这个例子中, 如果存储y的操作③标记为memory_order_release, 而非memory_order_relaxed的话, 释放栅栏②也会对这个操作产生影响。 同样的, 当加载y的操作④标记memory_order_acquire时, 获取栅栏⑤也会对之产生影响.

    2. 内存栅栏对非原子的操作排序

    #include <atomic>
    #include <thread>
    #include <assert.h>
    
    bool x=false;
    std::atomic<bool> y;
    std::atomic<int> z;
    
    void write_x_then_y()
    {
        x=true;// 1 在栅栏前存储x
        std::atomic_thread_fence(std::memory_order_release);
        y.store(true,std::memory_order_relaxed);// 2 在栅栏后存储y
    }
    
    void read_y_then_x()
    {
        while(!y.load(std::memory_order_relaxed));// 3 在#2写入前, 持续等待
        std::atomic_thread_fence(std::memory_order_acquire);
        if(x)// 4 这里读取到的值, 是#1中写入
            ++z;
    }
    
    int main()
    {
        x=false;
        y=false;
        z=0;
        std::thread a(write_x_then_y);
        std::thread b(read_y_then_x);
        a.join();
        b.join();
        assert(z.load()!=0);// 5 断言将不会触发
    }
    

    栅栏仍然为存储x①和存储y②, 还有加载y③和加载x④提供一个执行序列, 并且这里仍然有一
    个先行关系, 在存储x和加载x之间, 所以断言⑤不会被触发。 ②中的存储和③中对y的加载,
    都必须是原子操作
    ; 否则, 将会在y上产生条件竞争, 不过一旦读取线程看到存储到y的操
    作, 栅栏将会对x执行有序的操作。 这个执行顺序意味着, x上不存在条件竞争, 即使它被另
    外的线程修改或被其他线程读取。

    展开全文
  • 内存栅栏的影响

    2019-04-20 17:43:39
    为了保证线程共享变量的可见性,会使用到内存栅栏,jvm设置内存栅栏,并将共享数据及时刷新到主存中保证其他线程可以获得最新变量数据。在使用内存栅栏时,程序会被禁止重排序。如下: foo++; bar++; 对bar变量...
  • 4. 存储序列导致不必要的停顿 不幸的是,每个存储...此类情况可立即出现在内存栅栏之后,而所有后续存储指令必须等待使无效操作去完成,无论是否这些存储导致缓存未命中.  此状态可被改进通过使标记无效确认消息尽
  • 内存屏障 <1>volatile volatile的本意是“易变的” 因为访问寄存器要比访问内存单元快的多,所以编译器一般都会作减少存取内存的优化,但有可能会读脏数据。当要求使用volatile声明变量值的时候,系统总是...
  • 内存栅栏 笔记

    2019-04-29 19:55:08
    简单来说,内存栅栏就是从本地或工作内存到主存之间的拷贝动作。 仅当系操作线程先跨越内存栅栏而读线程后跨越内存栅栏的情况下,写操作线程所做的变更才对其他线程可见。 关键字synchronized 和volatile都强制...
  • http://download.csdn.net/download/programresearch/98296746. 样例 内存栅栏序列此段介绍一些巧妙,但隐约有问题的内存栅栏的使用.尽管它们中很多在大多数时候可以工作,并且一些在某些特定的CPU上可以一直工作,...
  • C++中提供了两种栅栏,内存栅栏(atomic_thread_fence)用于解决线程之间表现的内存乱序,其阻止CPU指令层面的乱序优化;编译栅栏(atomic_signal_fence)用于解决与信号处理程序(一种软中断程序)之间表现的内存...
  • Memory Barriers and Volatility (内存栅栏和易失字段 ) 考虑下下面的代码:  int  _answer;   bool  _complete;   void  A()  {  _answer  =   123 ;  _complete  =   true ;  } ...
  • Disruptor-NET和内存栅栏

    2017-08-01 15:16:00
    这时我们就需要显式的使用...这种指令称为内存栅栏。 内存一致性模型需要在各种的程序与系统的各个层次上定义内存访问的行为。在机器码与的层次上,其定义将影响硬件的设计者以及机器码开发人员;而在高级语言层次...
  • 内存屏障或内存栅栏【转】

    千次阅读 2014-09-30 21:49:26
    本文我将和大家讨论并发编程中最基础的一项技术:内存屏障或内存栅栏,也就是让一个CPU处理单元中的内存状态对其它处理单元可见的一项技术。 CPU使用了很多优化技术来实现一个目标:CPU执行单元的速度要远超主存...
  • 内存栅栏和volatile关键字

    千次阅读 2015-08-28 16:05:52
    内存栅栏和volatile关键字   前言   本次主要讲解关于内存栅栏的一点小东西,主要是扫盲,给大家普及普及概念性的东西.以前我们说过在一些简单的案例中,比如一个字段赋值或递增该字段,我们...
  • 内存栅栏和内存对齐

    2016-04-05 18:07:35
    Cache 一致性问题单核 Cache 中每个 Cache line 有2个标志:dirty 和 valid 标志,它们很好的描述了 ... 只有 Core 0 访问变量 x,它的 Cache line 数据和内存中的数据一致,数据只存在于本 Cache 中。  3个 Core...
  • 内存栅栏-Java

    2016-10-09 23:13:00
    什么是内存栅栏内存栅栏在x86架构上如何实现的? jdk8是如何调用这个系统底层api的? 转载于:https://my.oschina.net/pypy/blog/756027...
  • 文章目录参考内存屏障(内存栅栏) 参考 https://www.jianshu.com/p/64240319ed60 https://www.jianshu.com/p/08a0a8c984ab 内存屏障(内存栅栏) 内存屏障(Memory Barrier) 内存栅栏(Memory Fence) 因为编译器...
  • 内存栅栏:变量在进入内存栅栏并读取时,变量的值已经写入完毕,离开栅栏时,变量的值被读取时也已经写入完毕,只有一个线程能够进入内存栅栏,这保证了多线程的数据同步。 在上面这个例子中,我启动了三个线程。并...
  • 无锁编程与内存栅栏

    千次阅读 2016-01-25 19:45:03
    一个压箱底的问题是 levelDB 中的原子指针的实现:没有使用到锁,而是使用到了一个内存栅栏,以下是源码: 原子指针是什么?这个概念可能听得多,但用意何在估计很少有人能说得上来!这里我用白话去解释...
  • 在arm平台,相应的内存栅栏指令有三条,dmb(data memroy barrier),dsb(date synchronization barrier)和isb(instruction synchronization barrier)。dmb保证在dmb之前的内存访问指令在它之后的内存访问指令...
  • 这里记录下各种锁的使用和使用场景,在多线程场景开发时,我们经常遇到多个线程同时读写一块资源争抢一块资源的情况,比如同时读写同一个字段属性,同时对某个集合进行增删改查,同时对数据库进行读写(这里要用到...
  • 内存屏障 memory barrier,有时候也可以叫内存栅栏 memory fence。 现代Intel® CPU架构 还是先看看历史吧,从历史的发展中我们能够看到碰到的问题,以及解决问题的思路和具体实现,这样也就更深刻地理解为什么会是...
  • 内存栅栏volatile详解synchronized详解java锁优化Java线程中断Java的wait和notifyAbstractQueuedSynchronizer详解
  • 因翻译水平有限,如有不妥,敬请指正和谅解! 原文下载地址: http://download.csdn.net/download/programresearch/9829674是什么让疯狂的CPU...因此在像同步原语这样的事上,需要用内存栅栏来强制排序.同步原语操作依

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 10,553
精华内容 4,221
关键字:

内存栅栏

友情链接: zgwypaf.rar