c#执行顺序与语句编写顺序不符的案例分析

  介绍

这篇文章给大家分享的是有关c#执行顺序与语句编写顺序不符的案例分析的内容。小编觉得挺实用的,因此分享给大家做个参考。一起跟随小编过来看看吧。

编写程序的时候,人们的直观感觉通常认为,程序的执行顺序是按照语句的顺序进行的。然而,许多编程语言的规范是允许实际执行顺序与语句编写顺序不符的。实际上,编译器为了完成某种优化,常常会对一些操作进行适当的顺序调整,导致一些预料之外的现象。

首先,通过一个例子来展示这个现象。在一个c#。net核心3.1命令行程序中,定义两个全局变量a和b,在线程1中,依次对b和a进行递增。这样,在任何时刻b应当等于或+ 1。

静态int=0;
  静态int b=0;
  
  静态孔隙Thread1 ()
  {
  而(真)
  {
  + + b;
  + +;
  }
  }

在线程2中,先读取一个的值,然后执行一些其他操作,再读取b的值。如果语句一定是按顺序执行的,那么读取到的b的值应当比读取到的一个的值更新,从而b必然大于或等于一个(除非b发生了溢出)。编写程序,当b & lt;一个时输出它们的值。

静态int c=0;
  
  静态孔隙Thread2 ()
  {
  而(真)
  {
  c +=b;
  var localA=一个;
  c +=b;
  var localB=b;
  如果(localA比;localB)
  {
  Console.WriteLine (“a=b {localA}={localB}“);
  }
  }
  }

再编写主程序,启动上述的两个线程。

静态void Main (string [] args)
  {
  Task.Run (Thread1);
  Task.Run (Thread2);
  
  Console.ReadKey ();
  }

使用调试配置,编译并运行该程序,命令行是没有输出的,符合我们的预期。但是使用释放配置的话,就会出现大量输出,其中一个的值比b大1到5不等。

查看反汇编可以看的到,在第1个c +=b语句处,程序将b的值放到了寄存器中,而后面的语句均使用了该寄存器内存放的值,所以,编译器实际上将对b的读取操作合并并且前置了。以下为反汇编结果片段。

 00007 ffb628a394d mov rcx, 7 ffb6292fbd0h
  00007 ffb628a3957 mov edx, 1
  00007 ffb628a395c叫00007 ffbc2387b10
  00007 ffb628a3961 mov esi, dword ptr ffb6292fc08h [7]
  00007 ffb628a3967 mov连成一片,应急服务国际公司
  00007 ffb628a3969添加连成一片,dword ptr ffb6292fc0ch [7]
  00007字ffb628a396f mov ptr ffb6292fc0ch[7],连成一片
  var localA=一个;
  00007 ffb628a3975 mov edi, dword ptr ffb6292fc04h [7]
  c +=b;
  00007 ffb628a397b添加连成一片,应急服务国际公司
  c +=b;
  00007字ffb628a397d mov ptr ffb6292fc0ch[7],连成一片
  如果(localA比;localB)
  00007 ffb628a3983 cmp edi,应急服务国际公司
  00007 ffb628a3985 jle 00007 ffb628a394d 

在c#语言标准的基本概念一章执行顺序一节(参见:基本概念- C #语言规范)中,提到了c#的执行顺序规范C #程序的副作用在以下关键点处的顺序是被保留的:

    <李>对挥发性字段的读写 <李>锁语句 <李>线程的创建和终结
      李,

c#程序的执行顺序在满足以下条件的情况下,可以由执行环境任意调整的:

    <李>在同一线程内,数据的的依赖关系是被保留的。即,结果与语句按照顺序执行的情况一致。 <李>初始化顺序的规则是被保留的。 <李>相对于挥发性字段的读,写副作用的顺序是被保留的。
      李,

而上述的副作用包括:

    <李>读取或写入挥发性字段 <李>写入非挥发性变量 <李>写入外部资源李 <>李抛出异常
      李,

由此可以推出,c#程序中对非挥发性变量的读取顺序可能会被调整。在只有一个线程对该变量进行操作时,这个顺序的调整是保证不会影响结果的;但如果同时有其他的线程正在对变量进行修改,则读取的顺序是无法确定的。

因此,如果有多个线程同时访问的,对值的实时性有要求的变量,应当设置为挥发性变量。将上述实验中的静态变量a和b改为挥发性变量后,即使是释放配置下,也不会出现命令行的输出,即两个变量的读取顺序符合原始的语句顺序。

在c#程序中,读取非挥发性变量的顺序可能被执行环境任意调整。如果某个变量在被读取的时候会被其他线程写入,为了该读取结果的实时性,应当将该变量设置为挥发性变量。

感谢各位的阅读!关于c#执行顺序与语句编写顺序不符的案例分析就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到吧!

c#执行顺序与语句编写顺序不符的案例分析