易失用法的可重现示例 [英] A reproducible example of volatile usage

查看:77
本文介绍了易失用法的可重现示例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一个可复制的示例,该示例可以演示volatile关键字的工作方式.我正在寻找一种错误"的工作方式,而没有将变量标记为volatile,并且可以正确"地使用它.

I am look for a reproducible example that can demonstrate how volatile keyword works. I'm looking for something that works "wrong" without variable(s) marked as volatile and works "correctly" with it.

我的意思是说一个示例,该示例将演示执行期间的写/读操作顺序与未将变量未标记为volatile时的预期顺序不同,并且在未将变量未标记为volatile时也未更改.

I mean some example that will demonstrate that order of write/read operations during the execution is different from expected when variable is not marked as volatile and is not different when variable is not marked as volatile.

我以为我有一个例子,但是在其他人的帮助下,我意识到这只是一段错误的多线程代码. 为什么volatile和MemoryBarrier不能阻止操作重新排序?

I thought that I got an example but then with help from others I realized that it just was a piece of wrong multithreading code. Why volatile and MemoryBarrier do not prevent operations reordering?

我还找到了一个链接,该链接演示了volatile对优化器的影响,但与我正在寻找的不同.它说明了对标记为volatile的变量的请求不会得到优化.如何说明C#中volatile关键字的用法

I've also found a link that demonstrates an effect of volatile on the optimizer but it is different from what I'm looking for. It demonstrates that requests to variable marked as volatile will not be optimized out.How to illustrate usage of volatile keyword in C#

这是我到目前为止所到之处.此代码不显示任何读/写操作重新排序的迹象.我正在寻找一个可以显示的东西.

Here is where I got so far. This code does not show any signs of read/write operation reordering. I'm looking for one that will show.

    using System;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Runtime.CompilerServices;

    namespace FlipFlop
    {
        class Program
        {
            //Declaring these variables 
            static byte a;
            static byte b;

            //Track a number of iteration that it took to detect operation reordering.
            static long iterations = 0;

            static object locker = new object();

            //Indicates that operation reordering is not found yet.
            static volatile bool continueTrying = true;

            //Indicates that Check method should continue.
            static volatile bool continueChecking = true;

            static void Main(string[] args)
            {
                //Restarting test until able to catch reordering.
                while (continueTrying)
                {
                    iterations++;
                    a = 0;
                    b = 0;
                    var checker = new Task(Check);
                    var writter = new Task(Write);
                    lock (locker)
                    {
                        continueChecking = true;
                        checker.Start();

                    }
                    writter.Start();
                    checker.Wait();
                    writter.Wait();
                }
                Console.ReadKey();
            }

            static void Write()
            {
                //Writing is locked until Main will start Check() method.
                lock (locker)
                {
                    WriteInOneDirection();
                    WriteInOtherDirection();

                    //Stops spinning in the Check method.
                    continueChecking = false;
                }
            }

            [MethodImpl(MethodImplOptions.NoInlining)]
            static void WriteInOneDirection(){
                a = 1;
                b = 10;
            }

            [MethodImpl(MethodImplOptions.NoInlining)]
            static void WriteInOtherDirection()
            {
                b = 20;
                a = 2;
            }

            static void Check()
            {
                //Spins until finds operation reordering or stopped by Write method.
                while (continueChecking)
                {
                    int tempA = a;
                    int tempB = b;

                    if (tempB == 10 && tempA == 2)
                    {
                        continueTrying = false;
                        Console.WriteLine("Caught when a = {0} and b = {1}", tempA, tempB);
                        Console.WriteLine("In " + iterations + " iterations.");
                        break;
                    }
                }
            }
        }
    }

据我了解,导致重新排序的优化可能来自JITer或硬件本身.我可以改一下我的问题. JITer或x86 CPU是否对读/写操作进行重新排序,并且有办法在C#中对其进行演示?

As I understand an optimization that causes reordering can come from JITer or from hardware itself. I can rephrase my question. Does JITer or x86 CPUs reorder read/write operations AND is there a way to demonstrate it in C# if they do?

推荐答案

volatile 的确切语义是一个抖动实现细节.编译器会在您访问声明为volatile的变量时发出Opcodes.Volatile IL指令.它会进行一些检查以验证变量类型是否合法,不能声明大于4个字节的volatile类型的值类型,但这是buck停止的地方.

The exact semantics of volatile is a jitter implementation detail. The compiler emits the Opcodes.Volatile IL instruction where ever you access a variable that's declared volatile. It does some checking to verify that the variable type is legal, you can't declare value types larger than 4 bytes volatile but that's where the buck stops.

C#语言规范定义了 volatile 的行为,

The C# language specification defines the behavior of volatile, quoted here by Eric Lippert. The 'release' and 'acquire' semantics is something that only makes sense on a processor core with a weak memory model. Those kind of processors have not done well in the market, probably because they are such an enormous pain to program. The odds that your code will ever run on a Titanium are slim to none.

C#语言规范定义的特别糟糕之处在于,它根本没有提到真正会发生什么.声明变量volatile将防止抖动优化器优化将变量存储在cpu寄存器中的代码.这就是Marc链接的代码挂起的原因.这只会在当前的x86抖动下发生,这是 volatile 确实是一个抖动实现细节的另一个强烈暗示.

What's especially bad about the C# language specification definition is that it doesn't mention at all what really happens. Declaring a variable volatile prevents the jitter optimizer from optimizing the code to store the variable in a cpu register. Which is why the code that Marc linked is hanging. This will only happen with the current x86 jitter, another strong hint that volatile is really a jitter implementation detail.

volatile 的不良语义具有丰富的历史,它来自C语言.谁的代码生成器也很难正确设置它.这是一个有趣的有关此报告(pdf).它的历史可以追溯到2008年,有30多年的发展机会.否则,当代码优化器忘记了变量是易失性的时候,这会令人不寒而栗.未优化的代码永远不会有问题.值得注意的是,.NET(SSLI20)的开源"版本中的抖动完全忽略了IL指令.也可以说x86抖动的当前行为是一个错误.我认为这是不容易的,要使其进入故障模式是不容易的.但是没有人可以说它实际上是 一个错误.

The poor semantics of volatile has a rich history, it comes from the C language. Whose code generators have lots of trouble getting it right as well. Here's a interesting report about it (pdf). It dates from 2008, a good 30+ years of opportunity to get it right. Or wrong, this goes belly-up when the code optimizer is forgetting about a variable being volatile. Unoptimized code never has a problem with it. Notable is that the jitter in the 'open source' version of .NET (SSLI20) completely ignores the IL instruction. It can also be argued that the current behavior of the x86 jitter is a bug. I think it is, it is not easy to bump it into the failure mode. But nobody can argue that it actually is a bug.

写作是在墙上,只有将变量存储在内存映射的寄存器中时,才声明它为volatile.关键字的初衷.在C#语言中遇到这种用法的几率应该很小,这类代码属于设备驱动程序.最重要的是,从不假定它在多线程方案中很有用.

The writing is on the wall, only ever declare a variable volatile if it is stored in a memory mapped register. The original intention of the keyword. The odds that you'll run into such a usage in the C# language should be vanishingly small, code like that belongs in a device driver. And above all, never assume that it is useful in a multi-threading scenario.

这篇关于易失用法的可重现示例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆