.Net Core在X86上实现Interlocked.Increment(ref long)的方式

因为在X86上long会被分割为两个int进行操作, 那么Interlocked.Increment的实现成为了一个问题。
在一番搜索后未发现有现成的文章解释这个问题,于是我就动手分析了。
这篇是笔记,不会做过多的解释。

首先重现环境是 .Net Core 2.0 Windows (x86) Binaries, 下载可以到 https://www.microsoft.com/net/download/core#/sdk
重现的代码如下

using System;
using System.Threading;

namespace x86program
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.ReadLine();
            Console.WriteLine("Hello World!");
            Console.ReadLine();
            long a = 0x1234567887564321;
            Console.WriteLine(Interlocked.Increment(ref a));
        }
    }
}

需要的工具:
Visual Studio 2017 15.3 RTM
OllyDbg 1.1 (or 2.0)

首先下载了x86版的dotnet后,解压然后在命令行运行

F:\dotnet-sdk-2.0.0-win-x86\x86program>..\dotnet.exe run

运行后使用Visual Studio打开项目然后"附加到进程", 成功后在下图中的地方下断点

.Net Core在X86上实现Interlocked.Increment(ref long)的方式_第1张图片

然后命令行回车, 可以触发此断点, 我们可以看到 Interlocked.Increment 调用了 0x76A7CA0 处的函数, 传入参数只有一个, 就是指向long变量的指针

之后在Visual Studio中取消附加, 然后使用ollydbg的Attach, 成功后在 0x76A7CA0 下断点

.Net Core在X86上实现Interlocked.Increment(ref long)的方式_第2张图片

这个函数调用了函数 0x7428BE0, 传入了分割为两个int的long (1), ecx仍然指向原来的long变量

函数 0x7428BE0 是一个JIT桩(Stub), 第一次调用会触发JIT编译, 第二次调用会跳到JIT编译结果

.Net Core在X86上实现Interlocked.Increment(ref long)的方式_第3张图片

.Net Core在X86上实现Interlocked.Increment(ref long)的方式_第4张图片

JIT编译后的实现就在 0x3410F40 处,这里的就是 Interlocked.Increment(ref long) 的实现

.Net Core在X86上实现Interlocked.Increment(ref long)的方式_第5张图片

我们可以看到这个实现使用了x86的CMPXCHG8B指令,如果出现long变量的值被其他线程修改,会检测出来并重试添加

.Net Core在X86上实现Interlocked.Increment(ref long)的方式_第6张图片

当然,不是所有x86的CPU都支持CMPXCHG8B指令, 但至少可以运行.Net Core的CPU都会支持此指令, 也就是说实现 atomic long 不需要semaphore

http://www.geoffchappell.com/studies/windows/km/cpu/cx8.htm

上面的代码是Debug下编译得到的, Release下同样需要调用一个helper函数, 内部的逻辑是一样的

.Net Core在X86上实现Interlocked.Increment(ref long)的方式_第7张图片

x64位上的 Interlocked.Increment(ref long) 就很简单了, 可以使用现成的指令 lock xadd

.Net Core在X86上实现Interlocked.Increment(ref long)的方式_第8张图片

分析到此为止

=================================================================================

微软最近发布了新的JIT文档,比原来的文档要容易理解很多,有兴趣的可以去围观:

https://github.com/dotnet/coreclr/blob/master/Documentation/botr/ryujit-tutorial.md

下一篇CoreCLR源码探索会讲解JIT是如何实现的,但是还需要最少一个月的时间,有兴趣的请耐心等待。

你可能感兴趣的:(.Net Core在X86上实现Interlocked.Increment(ref long)的方式)