Volatile 类
定义
重要
一些信息与预发行产品相关,相应产品在发行之前可能会进行重大修改。 对于此处提供的信息,Microsoft 不作任何明示或暗示的担保。
包含用于执行可变内存操作的方法。
public ref class Volatile abstract sealedpublic static class Volatiletype Volatile = classPublic Class Volatile- 继承
- 
				Volatile
注解
在多处理器系统上,由于编译器或处理器中的性能优化,当多个处理器在同一内存上运行时,常规内存操作似乎被重新排序。 易失性内存操作阻止对操作进行某些类型的重新排序。 易失性写入操作可防止对线程的早期内存操作重新排序,以在易失性写入之后发生。 易失性读取操作可防止对线程的后续内存操作重新排序,以在易失读取之前发生。 这些操作可能涉及某些处理器上的内存屏障,这可能会影响性能。
例如,请考虑以下具有两个线程和两个 Int32 字段 x 且 y 最初为零的方案:
| 线程 1 | 线程 2 | 
|---|---|
| x = 1; | int y2 = Volatile.Read(ref y); | 
| Volatile.Write(ref y, 1); | int x2 = x; | 
易失性读取和写入会阻止每个线程中的两个操作(例如,由编译器或处理器)重新排序。 无论这些操作在一个线程上相对于另一个线程的实际发生顺序如何,即使在线程可能在不同的处理器上运行的多处理器系统上,可变操作都保证线程 2 不会看到 y2 == 1 和 x2 == 0。 在线程 1 上,对 x 的写入必须出现在对 的易失性写入y之前,在线程 2 上,对 的xy读取必须出现在易失性读取之后。 因此,如果线程 2 看到 y2 == 1,它也必须看到 x2 == 1。
但是,请考虑上述方案与操作发生的特定顺序相同的方案:
| 序列 | 线程 1 | 线程 2 | 
|---|---|---|
| 1 | x = 1; | ... | 
| 2 | Volatile.Write(ref y, 1); | ... | 
| 3 | ... | int y2 = Volatile.Read(ref y); | 
| 4 | ... | int x2 = x; | 
即使对线程 1 上的易失性写入 y 发生在线程 2 的易失性读取 y 之前,线程 2 仍可能看到 y2 == 0。 对 的易失性写入 y 不保证不同处理器上的后续易失读取 y 将看到更新的值。
注意
可变内存操作适用于同步的特殊情况,其中正常锁定不是可接受的替代方法。 在正常情况下,C# lock 语句、Visual Basic SyncLock 语句和 Monitor 类提供了同步数据访问的最简单且最不容易出错的方法,而 Lazy<T> 类提供了一种简单的方法来编写延迟初始化代码,而无需直接使用双重检查锁定。
Volatile.Read和 Volatile.Write 方法支持语言不支持的功能。 例如:
- 某些语言(如 Visual Basic)无法识别易失性内存操作的概念。 类 Volatile 以此类语言提供该功能。 - 注意 - 调用其中一种方法仅影响单个内存访问。 若要为字段提供有效的同步,对字段的所有访问都必须使用 Volatile.Read 和 Volatile.Write。 
- 在 C# 中,对 - volatile字段使用修饰符可以保证每次访问该字段都是易失性内存操作,但- volatile修饰符不能应用于数组元素。 Volatile.Read和 Volatile.Write 方法可用于数组元素。
方法
| Read(Boolean) | 读取指定字段的值。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之后,则处理器无法将其移至此方法之前。 | 
| Read(Byte) | 读取指定字段的值。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之后,则处理器无法将其移至此方法之前。 | 
| Read(Double) | 读取指定字段的值。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之后,则处理器无法将其移至此方法之前。 | 
| Read(Int16) | 读取指定字段的值。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之后,则处理器无法将其移至此方法之前。 | 
| Read(Int32) | 读取指定字段的值。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之后,则处理器无法将其移至此方法之前。 | 
| Read(Int64) | 读取指定字段的值。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之后,则处理器无法将其移至此方法之前。 | 
| Read(IntPtr) | 读取指定字段的值。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之后,则处理器无法将其移至此方法之前。 | 
| Read(SByte) | 读取指定字段的值。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之后,则处理器无法将其移至此方法之前。 | 
| Read(Single) | 读取指定字段的值。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之后,则处理器无法将其移至此方法之前。 | 
| Read(UInt16) | 读取指定字段的值。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之后,则处理器无法将其移至此方法之前。 | 
| Read(UInt32) | 读取指定字段的值。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之后,则处理器无法将其移至此方法之前。 | 
| Read(UInt64) | 读取指定字段的值。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之后,则处理器无法将其移至此方法之前。 | 
| Read(UIntPtr) | 读取指定字段的值。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之后,则处理器无法将其移至此方法之前。 | 
| Read<T>(T) | 从指定的字段读取对象引用。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之后,则处理器无法将其移至此方法之前。 | 
| ReadBarrier() | 包含用于执行可变内存操作的方法。 | 
| Write(Boolean, Boolean) | 将指定的值写入指定字段。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之前,则处理器无法将其移至此方法之后。 | 
| Write(Byte, Byte) | 将指定的值写入指定字段。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之前,则处理器无法将其移至此方法之后。 | 
| Write(Double, Double) | 将指定的值写入指定字段。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之前,则处理器无法将其移至此方法之后。 | 
| Write(Int16, Int16) | 将指定的值写入指定字段。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之前,则处理器无法将其移至此方法之后。 | 
| Write(Int32, Int32) | 将指定的值写入指定字段。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之前,则处理器无法将其移至此方法之后。 | 
| Write(Int64, Int64) | 将指定的值写入指定字段。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之前,则处理器无法将其移至此方法之后。 | 
| Write(IntPtr, IntPtr) | 将指定的值写入指定字段。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之前,则处理器无法将其移至此方法之后。 | 
| Write(SByte, SByte) | 将指定的值写入指定字段。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之前,则处理器无法将其移至此方法之后。 | 
| Write(Single, Single) | 将指定的值写入指定字段。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之前,则处理器无法将其移至此方法之后。 | 
| Write(UInt16, UInt16) | 将指定的值写入指定字段。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之前,则处理器无法将其移至此方法之后。 | 
| Write(UInt32, UInt32) | 将指定的值写入指定字段。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之前,则处理器无法将其移至此方法之后。 | 
| Write(UInt64, UInt64) | 将指定的值写入指定字段。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之前,则处理器无法将其移至此方法之后。 | 
| Write(UIntPtr, UIntPtr) | 将指定的值写入指定字段。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之前,则处理器无法将其移至此方法之后。 | 
| Write<T>(T, T) | 将指定的对象引用写入指定字段。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之前,则处理器无法将其移至此方法之后。 | 
| WriteBarrier() | 包含用于执行可变内存操作的方法。 |