你好,想在c#中创建一个内存屏障的图解。

问题描述 投票:0回答:1

我主动向我的团队提出了一个由指令重排而引入bug的情况,然而我对CPU、CLR和JIT的理解相当外行,我没能举出一个好例子。

下面我展示的是我想出的最好的办法,请大家从这里开始看代码片段来理解我说的是什么。

最主要的一点是在 thread2 的 如果声明如果我在线程1或线程2中手动重新排列指令->打印就会发生(即使你在线程2中交换c.x和c.y的读数,它也会因为竞赛条件而打印)。

我的想法是通过将相距较远的变量变成整数来强制重新安排x和z的写入,认为由于8个字节字的大小,它可以在一个cpu周期内同时写入它们,而不是3个周期写入4->8->4个字节。(我知道这实际上不是3个cpu周期,很不幸,我不懂汇编。) 我甚至在万不得已的情况下尝试把它放在一个结构体中,认为这样可以迫使JIT进行某种优化。

如果有任何帮助,我将非常感激,因为我非常渴望让它工作。(我也试着按照Joseph Albahari的电子书中的例子去做,但那些都没有用,这就是为什么我试着做一个更复杂的例子)。我也没有忘记用Release for x64指令集编译。

代码。

public class Program
{
    public static void Main()
    {
        var stopWatch = new Stopwatch();

        for (var i = 0; i < 100000000; i++)
        {
            var delegates = new MultiTreadingDelegates(i);

            Task.Run(delegates.Thread1);
            Task.Run(delegates.Thread2);
        }

        Console.WriteLine("finished");
        Console.ReadKey();
    }
}

public class MultiTreadingDelegates
{
    private int i = 0;

    private Container container = new Container();

    public MultiTreadingDelegates(int i)
    {
        this.i = i;
    }

    public void Thread1()
    {
        container.X = 10000000;
        container.Z = 6000000000;
        container.Y = 20000000;
    }

    public void Thread2()
    {
        int y = container.Y;
        long z = container.Z;
        int x = container.X;

        if (x != 0 && z == 0 && y != 0)
        {
            System.Console.WriteLine($"i = {i}{Environment.NewLine}"
                                     + $"x = {x}{Environment.NewLine}"
                                     + $"z = {z}{Environment.NewLine}"
                                     + $"y = {y}{Environment.NewLine}"
                                     );
        }
    }
}

public struct Container
{
    public int X;
    public long Z;
    public int Y;
}
c# volatile memory-barriers
1个回答
0
投票

我再次感谢大家的帮助。

class Program
{
    static void Main(string[] args)
    {
        Task.Run(DelegatesUsingPetersons.Thread1);
        Task.Run(DelegatesUsingPetersons.Thread2).GetAwaiter().GetResult();
    }
}

static class DelegatesUsingPetersons
{
    private static long x = 0;
    private static long y = 0;
    private static bool flag1 = false;
    private static bool flag2 = false;

    public static void Thread1()
    {
        while (true)
        {
            flag1 = true;
            /*Thread.MemoryBarrier();*/  //Uncomment to fix locking mechanism
            if (flag2 == false)
            {
                x++;
                y++;
            }
            flag1 = false;
        }
    }

    public static void Thread2()
    {
        long lx = 0;
        long ly = 0;

        while (true)
        {
            flag2 = true;
            /*Thread.MemoryBarrier();*/  //Uncomment to fix locking mechanism
            if (flag1 == false)
            {
                lx = x;
                ly = y;
            }
            flag2 = false;

            if (lx != ly)
            {
                Console.WriteLine($"lx={lx}, ly={ly} - OMG this cannot happen!");
            }
        }
    }
}

如果你想把它与一个 "更传统 "的工作代码并列,这里是同样的代码,只是没有Mr.Peterson做所有的花哨的算法巫术。

static class DelegatesUsingLock
{
    private static long x = 0;
    private static long y = 0;
    private static object loq = new object();

    public static void Thread1()
    {
        while (true)
        {
            if (Monitor.TryEnter(loq))
            {
                x++;
                y++;
                Monitor.Exit(loq);
            }
        }
    }

    public static void Thread2()
    {
        long lx = 0;
        long ly = 0;

        while (true)
        {
            if (Monitor.TryEnter(loq))
            {
                lx = x;
                ly = y;
                Monitor.Exit(loq);
            }

            if (lx != ly)
            {
                Console.WriteLine($"lx={lx}, ly={ly} - This Never Happens");
            }
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.