返回顶部
首页 > 资讯 > 精选 >C#中Volatile的使用方法有哪些
  • 440
分享到

C#中Volatile的使用方法有哪些

2023-06-25 14:06:51 440人浏览 安东尼
摘要

本篇内容介绍了“C#中Volatile的使用方法有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1.Overview经常研究.net源码

本篇内容介绍了“C#中Volatile的使用方法有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

1.Overview

经常研究.net源码库的小伙伴会经常看到一个关键字volatile,那它在开发当中的作用是什么呢?

我们一起来看看官方文档里是怎么描述的,如下:

volatile 关键字指示一个字段可以由多个同时执行的线程修改。出于性能原因,编译器,运行时系统甚至硬件都可能重新排列对存储器位置的读取和写入。声明为 volatile 的字段将从某些类型的优化中排除。不确保从所有执行线程整体来看时所有易失性写入操作均按执行顺序排序。”

本文将围绕这部分进行解读。

声明语法如下:

class VolatileTest{   public volatile int sharedStorage;      public void Test(int i)  {       sharedStorage = i;  }}

2.Detail

我们先了解一下前置知识点。

(1)在CLR中将对sbytebyteshortushortintuintcharfloatbool。以及引用类型保证读写时原子性的(long、double不是原子性读写)变量中的所有字节都是一次性写入或读取的。

(2)Framework Class Library(FCL) 保证所有静态方法都是线程安全的。这意味着假如两个线程同时调用一个静态方法,不会有数据被损坏。为什么?

public static string Print(String str){   string val = "";   val += str;   return val;}

因为静态方法内声明的变量,每个线程调用时都会新创建一份,而不会共用一个存储单元。比如这里的val每个线程都会创建自己的一份,因此不会有线程安全问题。注意:静态变量,由于是在类加载时占用一个存储区每个线程都是共用这个存储区的,所以如果在静态方法里使用了静态变量;这就会有线程安全问题。

(3)内存、CPU缓存(注:下列为简述内容,实际上不仅如此)

CPU缓存,CPU集成的缓存。

内存,内存条硬件提供的存储空间。

我们继续回到主要内容上,用下面的若干代码示例来表达volatile的作用。

public class Program{       public static int bookNum = 0;       public static void Main(string[] args)      {           Console.WriteLine("juster书的数量:" + bookNum);           Thread juster = new Thread(() =>          {               Console.WriteLine("juster没带书,等待家长送书到学校...");               while (bookNum == 0) {}               Console.WriteLine("juster拿到书,开始上课听讲。");          });           juster.Name = nameof(juster);           juster.Start();           Thread parent = new Thread(() =>          {               Console.WriteLine("parent在屋里找书中...");               Thread.Sleep(2000);               Console.WriteLine("parent找到了书之后,送往学校...");               SendBook();          });           parent.Name = nameof(parent);           parent.Start();      }       public static void SendBook()      {           bookNum = 1;      }}

代码执行输出如下:

C#中Volatile的使用方法有哪些

这时候诡异的来了,按照正常的代码执行逻辑不难看出当parent线程执行Sendbook()的时候juster应该就能拿到书上课了。但是这里juster却一直没有拿到是为什么呢?

心细的小伙伴应该观察到了这里的运行模式是Release,众所周知Release是.Net的发布版本执行效率会比Debug版本要高。

为什么Release版本效率高呢?怎么得来的?下面这段代码来解释:

C#中Volatile的使用方法有哪些

上面这张反编译的图不难看出,10*10-100这段代码直接编译成0了。这种现象是因为Release编译的时候编译器会对代码进行‘优化'。这段是最直观能看到的‘优化'效果,其实C#编译器将你的代码转换成中间语言(IL)。然后,JIT将IL转换成本机CPU指令。此外,C#编译器、JIT编译器,甚至CPU本身都可能优化你的代码。

但是实际上在上述代码中count的值始终为0;所以循环永远不会执行,没有必要编译循环内的代码在编译后会被‘优化'。说了这么多,只是为了给大伙证明Release编译这一层会存在‘优化';接下来继续回到volatile上。

说到这里,如何解决各种‘优化'带来的问题呢?这时候只需要在booknum前面加上volatile关键字修饰即可。

public class Program{       public static volatile int bookNum = 0;       public static void Main(string[] args)      {           Console.WriteLine("juster书的数量:" + bookNum);           Thread juster = new Thread(() =>          {               Console.WriteLine("juster没带书,等待家长送书到学校...");               while (bookNum == 0) { }               Console.WriteLine("juster拿到书,开始上课听讲。");          });           juster.Name = nameof(juster);           juster.Start();           Thread parent = new Thread(() =>          {               Console.WriteLine("parent在屋里找书中...");               Thread.Sleep(2000);               Console.WriteLine("parent找到了书之后,送往学校...");               SendBook();          });           parent.Name = nameof(parent);           parent.Start();      }       public static void SendBook()      {           bookNum = 1;      }}

C#中Volatile的使用方法有哪些

在被各种优化之后,booknum因为是值类型在每个线程访问时会发生复制且又是在静态方法中被修改。所以每个线程都会复制booknum的值到当前线程上下文中缓存起来。这样就导致了parent线程修改了booknum的值juster线程看不到的情况。这个时候就需要用volatile关键字告诉编译器不需要这样的优化,表示用volatile定义的变量会被改变,每次都必须从内存中读取,而不能把他放在CPU cache或寄存器中重复使用。最后booknum会在运行的过程中修改值且其他线程能‘共享访问'达到最终的效果。

3.Conclusion

Part1

volatile 关键字可应用于以下类型的字段:

  • 引用类型。

  • 指针类型(在不安全的上下文中)。请注意,虽然指针本身可以是可变的,但是它指向的对象不能是可变的。换句话说,不能声明“指向可变对象的指针”。

  • 简单类型,如 sbytebyteshortushortintuintcharfloatbool

  • 具有以下基本类型之一的 enum 类型:bytesbyteshortushortintuint

  • 已知为引用类型的泛型类型参数。

  • IntPtr 和 UIntPtr。

其他类型(包括 doublelong)无法标记为 volatile,因为对这些类型的字段的读取和写入不能保证是原子的。若要保护对这些类型字段的多线程访问,请使用 Interlocked 类成员或使用 lock 语句保护访问权限。

volatile 关键字只能应用于 classstruct 的字段。不能将局部变量声明为 volatile

Part2

volatile并不能用来做线程同步,它的主要作用时为了让多个线程之间能看到被修改过后最新的值。

C#中Volatile的使用方法有哪些

Part3

C#不支持以传递引用的方式将volatile字段传给方法。

int.TryParse("123", out x);

Part4

除了禁止编译优化,还有同步到内存中因为CPU每个核心都有自己Cache所以需要同步到内存中方便其他核心使用。

Part5

看完本文也能解开小白时期的疑惑,为什么我写代码编译成release版本之后就不能运行报错的奇特现象了。

Part6

volatile 牵扯到的相关知识点和原理远远不止这些。

“C#中Volatile的使用方法有哪些”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: C#中Volatile的使用方法有哪些

本文链接: https://lsjlt.com/news/305580.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C#中Volatile的使用方法有哪些
    本篇内容介绍了“C#中Volatile的使用方法有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1.Overview经常研究.NET源码...
    99+
    2023-06-25
  • c语言volatile的作用有哪些
    C语言中的volatile关键字主要有以下几个作用:1. 防止编译器对变量的优化:编译器在优化代码时可能会对变量进行优化,如将变量缓...
    99+
    2023-09-04
    c语言
  • C++ 函数volatile关键字的用法有哪些?
    c++++ 的 volatile 关键字用于告知编译器特定变量或函数不会被优化,防止优化、确保原子访问和直接访问低级硬件操作。它可以防止编译器对标记为 volatile 的变量进行不安全...
    99+
    2024-04-12
    函数 volatile c++
  • c#中gdi的使用方法有哪些
    在C#中,GDI(Graphics Device Interface)用于处理图形和图像的绘制和操作。以下是一些常见的使用方法:1....
    99+
    2023-08-21
    c#
  • c++中cast的使用方法有哪些
    在C++中,有四种类型的cast,分别是static_cast、dynamic_cast、const_cast和reinterpre...
    99+
    2024-03-12
    c++
  • C++的vector使用方法有哪些
    这篇文章主要讲解了“C++的vector使用方法有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++的vector使用方法有哪些”吧!C++vector 用法整理1.头文件#inclu...
    99+
    2023-06-29
  • c#使用listbox的方法有哪些
    在C#中,可以使用ListBox控件的方法包括但不限于以下几种:1. Add方法:向ListBox中添加项。```csharplis...
    99+
    2023-08-09
    c# listbox
  • C++11的bitset使用方法有哪些
    本篇内容介绍了“C++11的bitset使用方法有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!构造bitset对象构造16位的b1,每...
    99+
    2023-06-19
  • C#中泛型集合的使用方法有哪些
    今天小编给大家分享一下C#中泛型集合的使用方法有哪些的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。SortedList<...
    99+
    2023-07-04
  • c#中PrepareCommand()方法的作用有哪些
    在C#中,PrepareCommand()方法的作用主要有以下几个: 为数据库连接创建一个新的Command对象。 预编译SQL语...
    99+
    2023-10-27
    c#
  • volatile在c语言中的用法
    volatile关键字用于指示变量的值可能被外部因素更改,尤其是在硬件寄存器访问、共享内存和中断服务例程中。它防止编译器优化,提高可移植性和安全性,但有轻微的性能开销,应谨慎使用并限定作...
    99+
    2024-04-28
    c语言 作用域
  • C# Regex类中常用的方法有哪些
    这篇文章主要讲解了“C# Regex类中常用的方法有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C# Regex类中常用的方法有哪些”吧!Regex 类Regex 类用于表示一个正则表...
    99+
    2023-06-17
  • C# .NET使用操作符的方法有哪些
    这篇文章主要介绍“C# .NET使用操作符的方法有哪些”,在日常操作中,相信很多人在C# .NET使用操作符的方法有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C# .NET使用操作符的方法有哪些”的疑...
    99+
    2023-06-03
  • C# Volatile的具体使用
    目录​1.Overview2.Detail3.Conclusion4.Reference​1.Overview 经常研究.NET源码库的小伙伴会经常看到一个关...
    99+
    2024-04-02
  • HTML5中Canvas的使用方法有哪些
    这篇文章主要介绍了HTML5中Canvas的使用方法有哪些,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。   moveTo(x,y) 定义...
    99+
    2024-04-02
  • java中velocity的使用方法有哪些
    在Java中使用Velocity模板引擎有以下几种方法:1. 使用Velocity的原始API:通过创建Velocity引擎实例,加...
    99+
    2023-09-16
    java velocity
  • Linux中FirewallD的使用方法有哪些
    本篇内容介绍了“Linux中FirewallD的使用方法有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!centos 7中防火墙Fire...
    99+
    2023-06-27
  • jquery中animate使用的方法有哪些
    在jQuery中,animate方法用于创建自定义的动画效果。以下是animate方法的常用使用方法:1. animate(properties, duration, easing, complete):这是animate方法的基本形式...
    99+
    2023-08-09
    jquery animate
  • Android中ListView的使用方法有哪些
    在Android中,可以使用以下几种方法来使用ListView:1. 使用ArrayAdapter:可以使用ArrayAdapter...
    99+
    2023-08-16
    Android ListView
  • Mybatisplus中QueryWrapper的使用方法有哪些
    这篇文章主要介绍“Mybatisplus中QueryWrapper的使用方法有哪些”,在日常操作中,相信很多人在Mybatisplus中QueryWrapper的使用方法有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希...
    99+
    2023-07-05
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作