Disruptor-NET算法(是一种无锁算法)需要我们自己实现某一种特定的内存操作的语义以保证算法的正确性。这时我们就需要显式的使用一些指令来控制内存操作指令的顺序以及其可见性定义。这种指令称为内存栅栏。

内存一致性模型需要在各种的程序与系统的各个层次上定义内存访问的行为。在机器码与的层次上,其定义将影响硬件的设计者以及机器码开发人员;而在高级语言层次上,其定义将影响高级语言开发人员以及编译器开发人员和硬件设计人员。即,内存操作的乱序在各个层次都是存在的。这里,所谓的程序的执行顺序有三种:

(1)程序顺序:指在特定CPU上运行的,执行内存操作的代码的顺序。这指的是编译好的程序二进制镜像中的指令的顺序。编译器并不一定严格按照程序的顺序进行二进制代码的编排。编译器可以按照既定的规则,在执行代码优化的时候打乱指令的执行顺序,也就是上面说的程序顺序。并且,编译器可以根据程序的特定行为进行性能优化,这种优化可能改变算法的形式与算法的执行复杂度。(例如将switch转化为表驱动序列)
(2)执行顺序:指在CPU上执行的独立的内存相关的代码执行的顺序。执行顺序和程序顺序可能不同,这种不同是编译器和CPU优化造成的结果。CPU在执行期(Runtime)根据自己的内存模型(跟编译器无关)打乱已经编译好了的指令的顺序,以达到程序的优化和最大限度的资源利用。

(3)感知顺序:指特定的CPU感知到他自身的或者其他CPU对内存进行操作的顺序。感知顺序和执行顺序可能还不一样。这是由于缓存优化或者内存优化系统造成的。

而最终的共享内存模型的表现形式是由这三种“顺序”共同决定的。即从源代码到最终执行进行了至少三个层次上的代码顺序调整,分别是由编译器和CPU完成的。我们上面提到,这种代码执行顺序的改变虽然在单线程程序中不会引发副作用,但是在多线程程序中,这种作用是不能够被忽略的,甚至可能造成完全错误的结果。因此,在多线程程序中,我们有时需要人为的限制内存执行的顺序。而这种限制是通过不同层次的内存栅栏完成的。

Thread.MemoryBarrier就是采用了CPU提供的某些特定的指令的内存栅栏,下面是msdn的解释【http://msdn.microsoft.com/zh-cn/library/vstudio/system.threading.thread.memorybarrier(v=vs.100).aspx】:

Thread.MemoryBarrier: 按如下方式同步内存访问:执行当前线程的处理器在对指令重新排序时,不能采用先执行 MemoryBarrier 调用之后的内存访问,再执行 MemoryBarrier 调用之前的内存访问的方式。

按照我个人的理解:就是写完数据之后,调用MemoryBarrier,数据就会立即刷新,另外在读取数据之前调用MemoryBarrier可以确保读取的数据是最新的,并且处理器对MemoryBarrier的优化小心处理。

        int _answer;
bool _complete; void A()
{
_answer = 123;
Thread.MemoryBarrier(); //在写完之后,创建内存栅栏
_complete = true;
Thread.MemoryBarrier();//在写完之后,创建内存栅栏
} void B()
{
Thread.MemoryBarrier();//在读取之前,创建内存栅栏
if (_complete)
{
Thread.MemoryBarrier();//在读取之前,创建内存栅栏
Console.WriteLine(_answer);
}
}

Disruptor-NET正是通过Thread.MemoryBarrier 实现无锁和线程安全的内存操作,看下面是他的Atomic的Volatile类对常用数据类型的封装,volatile可以阻止代码重排序,并且值被更新的时候,会导致缓存失效,强制回写到主存中。

/// <summary>
/// An integer value that may be updated atomically
/// </summary>
public struct Integer
{
private int _value; /// <summary>
/// Create a new <see cref="Integer"/> with the given initial value.
/// </summary>
/// <param name="value">Initial value</param>
public Integer(int value)
{
_value = value;
} /// <summary>
/// Read the value without applying any fence
/// </summary>
/// <returns>The current value</returns>
public int ReadUnfenced()
{
return _value;
} /// <summary>
/// Read the value applying acquire fence semantic
/// </summary>
/// <returns>The current value</returns>
public int ReadAcquireFence()
{
var value = _value;
Thread.MemoryBarrier();
return value;
} /// <summary>
/// Read the value applying full fence semantic
/// </summary>
/// <returns>The current value</returns>
public int ReadFullFence()
{
var value = _value;
Thread.MemoryBarrier();
return value;
} /// <summary>
/// Read the value applying a compiler only fence, no CPU fence is applied
/// </summary>
/// <returns>The current value</returns>
[MethodImpl(MethodImplOptions.NoOptimization)]
public int ReadCompilerOnlyFence()
{
return _value;
} /// <summary>
/// Write the value applying release fence semantic
/// </summary>
/// <param name="newValue">The new value</param>
public void WriteReleaseFence(int newValue)
{
_value = newValue;
Thread.MemoryBarrier();
} /// <summary>
/// Write the value applying full fence semantic
/// </summary>
/// <param name="newValue">The new value</param>
public void WriteFullFence(int newValue)
{
_value = newValue;
Thread.MemoryBarrier();
} /// <summary>
/// Write the value applying a compiler fence only, no CPU fence is applied
/// </summary>
/// <param name="newValue">The new value</param>
[MethodImpl(MethodImplOptions.NoOptimization)]
public void WriteCompilerOnlyFence(int newValue)
{
_value = newValue;
} /// <summary>
/// Write without applying any fence
/// </summary>
/// <param name="newValue">The new value</param>
public void WriteUnfenced(int newValue)
{
_value = newValue;
} /// <summary>
/// Atomically set the value to the given updated value if the current value equals the comparand
/// </summary>
/// <param name="newValue">The new value</param>
/// <param name="comparand">The comparand (expected value)</param>
/// <returns></returns>
public bool AtomicCompareExchange(int newValue, int comparand)
{
return Interlocked.CompareExchange(ref _value, newValue, comparand) == comparand;
} /// <summary>
/// Atomically set the value to the given updated value
/// </summary>
/// <param name="newValue">The new value</param>
/// <returns>The original value</returns>
public int AtomicExchange(int newValue)
{
return Interlocked.Exchange(ref _value, newValue);
} /// <summary>
/// Atomically add the given value to the current value and return the sum
/// </summary>
/// <param name="delta">The value to be added</param>
/// <returns>The sum of the current value and the given value</returns>
public int AtomicAddAndGet(int delta)
{
return Interlocked.Add(ref _value, delta);
} /// <summary>
/// Atomically increment the current value and return the new value
/// </summary>
/// <returns>The incremented value.</returns>
public int AtomicIncrementAndGet()
{
return Interlocked.Increment(ref _value);
} /// <summary>
/// Atomically increment the current value and return the new value
/// </summary>
/// <returns>The decremented value.</returns>
public int AtomicDecrementAndGet()
{
return Interlocked.Decrement(ref _value);
} /// <summary>
/// Returns the string representation of the current value.
/// </summary>
/// <returns>the string representation of the current value.</returns>
public override string ToString()
{
var value = ReadFullFence();
return value.ToString();
}
}
        /// <summary>
        /// An integer value that may be updated atomically and is guaranteed to live on its own cache line (to prevent false sharing)
        /// </summary>
        [StructLayout(LayoutKind.Explicit, Size = CacheLineSize * 2)]
        public struct PaddedInteger
        {
            [FieldOffset(CacheLineSize)]
            private int _value;             /// <summary>
            /// Create a new <see cref="PaddedInteger"/> with the given initial value.
            /// </summary>
            /// <param name="value">Initial value</param>
            public PaddedInteger(int value)
            {
                _value = value;
            }             /// <summary>
            /// Read the value without applying any fence
            /// </summary>
            /// <returns>The current value</returns>
            public int ReadUnfenced()
            {
                return _value;
            }             /// <summary>
            /// Read the value applying acquire fence semantic
            /// </summary>
            /// <returns>The current value</returns>
            public int ReadAcquireFence()
            {
                var value = _value;
                Thread.MemoryBarrier();
                return value;
            }             /// <summary>
            /// Read the value applying full fence semantic
            /// </summary>
            /// <returns>The current value</returns>
            public int ReadFullFence()
            {
                var value = _value;
                Thread.MemoryBarrier();
                return value;
            }             /// <summary>
            /// Read the value applying a compiler only fence, no CPU fence is applied
            /// </summary>
            /// <returns>The current value</returns>
            [MethodImpl(MethodImplOptions.NoOptimization)]
            public int ReadCompilerOnlyFence()
            {
                return _value;
            }             /// <summary>
            /// Write the value applying release fence semantic
            /// </summary>
            /// <param name="newValue">The new value</param>
            public void WriteReleaseFence(int newValue)
            {
                _value = newValue;
                Thread.MemoryBarrier();
            }             /// <summary>
            /// Write the value applying full fence semantic
            /// </summary>
            /// <param name="newValue">The new value</param>
            public void WriteFullFence(int newValue)
            {
                _value = newValue;
                Thread.MemoryBarrier();
            }             /// <summary>
            /// Write the value applying a compiler fence only, no CPU fence is applied
            /// </summary>
            /// <param name="newValue">The new value</param>
            [MethodImpl(MethodImplOptions.NoOptimization)]
            public void WriteCompilerOnlyFence(int newValue)
            {
                _value = newValue;
            }             /// <summary>
            /// Write without applying any fence
            /// </summary>
            /// <param name="newValue">The new value</param>
            public void WriteUnfenced(int newValue)
            {
                _value = newValue;
            }             /// <summary>
            /// Atomically set the value to the given updated value if the current value equals the comparand
            /// </summary>
            /// <param name="newValue">The new value</param>
            /// <param name="comparand">The comparand (expected value)</param>
            /// <returns></returns>
            public bool AtomicCompareExchange(int newValue, int comparand)
            {
                return Interlocked.CompareExchange(ref _value, newValue, comparand) == comparand;
            }             /// <summary>
            /// Atomically set the value to the given updated value
            /// </summary>
            /// <param name="newValue">The new value</param>
            /// <returns>The original value</returns>
            public int AtomicExchange(int newValue)
            {
                return Interlocked.Exchange(ref _value, newValue);
            }             /// <summary>
            /// Atomically add the given value to the current value and return the sum
            /// </summary>
            /// <param name="delta">The value to be added</param>
            /// <returns>The sum of the current value and the given value</returns>
            public int AtomicAddAndGet(int delta)
            {
                return Interlocked.Add(ref _value, delta);
            }             /// <summary>
            /// Atomically increment the current value and return the new value
            /// </summary>
            /// <returns>The incremented value.</returns>
            public int AtomicIncrementAndGet()
            {
                return Interlocked.Increment(ref _value);
            }             /// <summary>
            /// Atomically increment the current value and return the new value
            /// </summary>
            /// <returns>The decremented value.</returns>
            public int AtomicDecrementAndGet()
            {
                return Interlocked.Decrement(ref _value);
            }             /// <summary>
            /// Returns the string representation of the current value.
            /// </summary>
            /// <returns>the string representation of the current value.</returns>
            public override string ToString()
            {
                var value = ReadFullFence();
                return value.ToString();
            }
        }

PaddedInteger类,它使用了7个Integer,加上一个对象头,刚好64个字节。

Disruptor-net  3.2.0

disruptor学习笔记

Disruptor原理剖析

剖析Disruptor:为什么会这么快?(二)神奇的缓存行填充

深入浅出多线程系列之八:内存栅栏和volatile 关键字

Disruptor-NET和内存栅栏的更多相关文章

  1. 第二节:深入剖析Thread的五大方法、数据槽、内存栅栏。

    一. Thread及其五大方法 Thread是.Net最早的多线程处理方式,它出现在.Net1.0时代,虽然现在已逐渐被微软所抛弃,微软强烈推荐使用Task(后面章节介绍),但从多线程完整性的角度上来 ...

  2. 内存栅栏(memory barrier):解救peterson算法的应用陷阱

    最近一个项目中用到了peterson算法来做临界区的保护,简简单单的十几行代码,就能实现两个线程对临界区的无锁访问,确实很精炼.但是在这不是来分析peterson算法的,在实际应用中发现peterso ...

  3. memory barrier 内存栅栏 并发编程

    并发编程 memory barrier (内存栅栏) CPU级 1.CPU中有多条流水线,执行代码时,会并行进行执行代码,所以CPU需要把程序指令 分配给每个流水线去分别执行,这个就是乱序执行: 2. ...

  4. 强如 Disruptor 也发生内存溢出?

    前言 OutOfMemoryError 问题相信很多朋友都遇到过,相对于常见的业务异常(数组越界.空指针等)来说这类问题是很难定位和解决的. 本文以最近碰到的一次线上内存溢出的定位.解决问题的方式展开 ...

  5. Disruptor——一种可替代有界队列完成并发线程间数据交换的高性能解决方案

    本文翻译自LMAX关于Disruptor的论文,同时加上一些自己的理解和标注.Disruptor是一个高效的线程间交换数据的基础组件,它使用栅栏(barrier)+序号(Sequencing)机制协调 ...

  6. 从零开始实现lmax-Disruptor队列(六)Disruptor 解决伪共享、消费者优雅停止实现原理解析

    MyDisruptor V6版本介绍 在v5版本的MyDisruptor实现DSL风格的API后.按照计划,v6版本的MyDisruptor作为最后一个版本,需要对MyDisruptor进行最终的一些 ...

  7. JVM内存模型、指令重排、内存屏障概念解析

    在高并发模型中,无是面对物理机SMP系统模型,还是面对像JVM的虚拟机多线程并发内存模型,指令重排(编译器.运行时)和内存屏障都是非常重要的概念,因此,搞清楚这些概念和原理很重要.否则,你很难搞清楚哪 ...

  8. 内存管理_深入剖析volatile关键字

    四.深入剖析volatile关键字 在前面讲述了很多东西,其实都是为讲述volatile关键字作铺垫,那么接下来我们就进入主题. 1.volatile关键字的两层语义 一旦一个共享变量(类的成员变量. ...

  9. Java内存访问重排序笔记

    >>关于重排序 重排序通常是编译器或运行时环境为了优化程序性能而采取的对指令进行重新排序执行的一种手段. 重排序分为两类:编译期重排序和运行期重排序,分别对应编译时和运行时环境. > ...

随机推荐

  1. LeetCode 368

    题目描述: Given a set of distinct positive integers, find the largest subset such that every pair (Si, S ...

  2. javaScript事件(一)事件流

    一.事件 事件是用户或浏览器自身执行的某种动作,如click,load和mouseover都是事件的名字.事件是javaScript和DOM之间的桥梁.你若触发,我便执行——事件发生,调用它的处理函数 ...

  3. pkcs1与pkcs8格式RSA私钥互相转换

    转自:http://blog.csdn.net/duan19056/article/details/52104966 1.PKCS1私钥生成 openssl genrsa -out private.k ...

  4. APP产品交互设计资源汇总(不断更新中...)

    Axure RP 7 元件库 http://www.iaxure.com/tag/axure7-0%E5%85%83%E4%BB%B6%E5%BA%93 ios8组合元件库V1.2版 http://w ...

  5. 「转载」关于Service常驻内存不被清理

    http://www.cnblogs.com/fangyucun/p/3533731.html 作个记录

  6. 用 IIS 实现请求转发

    最近部门要开发一个简单的APP,部分数据是现有项目已经存在的,为了方便维护,希望只提供一个交互的入口,并且协议的规则不变. 基于这个需求,有两套解决方案: 1.用代码将现有的api封装一层,对请求数据 ...

  7. 【Hibernate框架】关联映射(一对一关联映射)

    一.整理思路: 之前,小编总结过Mybatis的关联映射,接下来,再来总结一下hibernate的相关的关联映射,直接上图: 这张图,就是小编整理总结整个Hibernate的关联映射的一个大致思路. ...

  8. Oracle VM VirtualBox 安装CentOS 配置图形界面记录

    su yum groupinstall "X Window System" -y yum groupinstall "Desktop" -y 最后运行#star ...

  9. VS下运行项目时,检测到在集成的托管管道模式下不适用的 ASP.NET 设置。

    vs2012调试时默认会是集成模式,vs2012调试时怎么使用传统模式哪? 这个时候只要选中启动项目按F4,在托管管道模式里选传统模式即可!

  10. laravel 框架使用总结 limit

    后台开发就是数据的各种处理很多时候需要做到分页,但是在laravel中使用limit做分页的时候会出现问题,偏移量和每页的条数放进去好像不好使了 下面推荐给大家一种在laravel框架中非常好用的写法 ...