Volatile 类
定义
重要
一些信息与预发行产品相关,相应产品在发行之前可能会进行重大修改。 对于此处提供的信息,Microsoft 不作任何明示或暗示的担保。
包含用于执行可变内存操作的方法。
public ref class Volatile abstract sealed
public static class Volatile
type Volatile = class
Public 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 上,对 的x
y
读取必须出现在易失性读取之后。 因此,如果线程 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) |
从指定的字段读取对象引用。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之后,则处理器无法将其移至此方法之前。 |
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) |
将指定的对象引用写入指定字段。 在需要进行此操作的系统上,插入防止处理器重新对内存操作进行排序的内存屏障,如下所示:如果读取或写入操作在代码中出现在此方法之前,则处理器无法将其移至此方法之后。 |