volatile(C# 参考)volatile (C# Reference)

volatile 关键字指示一个字段可以由多个同时执行的线程修改。The volatile keyword indicates that a field might be modified by multiple threads that are executing at the same time. 出于性能原因,编译器,运行时系统甚至硬件都可能重新排列对存储器位置的读取和写入。The compiler, the runtime system, and even hardware may rearrange reads and writes to memory locations for performance reasons. 声明了 volatile 的字段不进行这些优化。Fields that are declared volatile are not subject to these optimizations. 添加 volatile 修饰符可确保所有线程观察易失性写入操作(由任何其他线程执行)时的观察顺序与写入操作的执行顺序一致。Adding the volatile modifier ensures that all threads will observe volatile writes performed by any other thread in the order in which they were performed. 不确保从所有执行线程整体来看时所有易失性写入操作均按执行顺序排序。There is no guarantee of a single total ordering of volatile writes as seen from all threads of execution.

volatile 关键字可应用于以下类型的字段:The volatile keyword can be applied to fields of these types:

  • 引用类型。Reference types.
  • 指针类型(在不安全的上下文中)。Pointer types (in an unsafe context). 请注意,虽然指针本身可以是可变的,但是它指向的对象不能是可变的。Note that although the pointer itself can be volatile, the object that it points to cannot. 换句话说,不能声明“指向可变对象的指针”。In other words, you cannot declare a "pointer to volatile."
  • 简单类型,如 sbytebyteshortushortintuintcharfloatboolSimple types such as sbyte, byte, short, ushort, int, uint, char, float, and bool.
  • 具有以下基本类型之一的 enum 类型:bytesbyteshortushortintuintAn enum type with one of the following base types: byte, sbyte, short, ushort, int, or uint.
  • 已知为引用类型的泛型类型参数。Generic type parameters known to be reference types.
  • IntPtrUIntPtrIntPtr and UIntPtr.

其他类型(包括 doublelong)无法标记为 volatile,因为对这些类型的字段的读取和写入不能保证是原子的。Other types, including double and long, cannot be marked volatile because reads and writes to fields of those types cannot be guaranteed to be atomic. 若要保护对这些类型字段的多线程访问,请使用 Interlocked 类成员或使用 lock 语句保护访问权限。To protect multi-threaded access to those types of fields, use the Interlocked class members or protect access using the lock statement.

volatile 关键字只能应用于 classstruct 的字段。The volatile keyword can only be applied to fields of a class or struct. 不能将局部变量声明为 volatileLocal variables cannot be declared volatile.

示例Example

下面的示例说明如何将公共字段变量声明为 volatileThe following example shows how to declare a public field variable as volatile.

class VolatileTest
{
    public volatile int sharedStorage;

    public void Test(int _i)
    {
        sharedStorage = _i;
    }
}

下面的示例演示如何创建辅助线程,并用它与主线程并行执行处理。The following example demonstrates how an auxiliary or worker thread can be created and used to perform processing in parallel with that of the primary thread. 有关多线程处理的详细信息,请参阅托管线程处理For more information about multithreading, see Managed Threading.

public class Worker
{
    // This method is called when the thread is started.
    public void DoWork()
    {
        bool work = false;
        while (!_shouldStop)
        {
            work = !work; // simulate some work
        }
        Console.WriteLine("Worker thread: terminating gracefully.");
    }
    public void RequestStop()
    {
        _shouldStop = true;
    }
    // Keyword volatile is used as a hint to the compiler that this data
    // member is accessed by multiple threads.
    private volatile bool _shouldStop;
}

public class WorkerThreadExample
{
    public static void Main()
    {
        // Create the worker thread object. This does not start the thread.
        Worker workerObject = new Worker();
        Thread workerThread = new Thread(workerObject.DoWork);

        // Start the worker thread.
        workerThread.Start();
        Console.WriteLine("Main thread: starting worker thread...");

        // Loop until the worker thread activates.
        while (!workerThread.IsAlive)
            ;

        // Put the main thread to sleep for 500 milliseconds to
        // allow the worker thread to do some work.
        Thread.Sleep(500);

        // Request that the worker thread stop itself.
        workerObject.RequestStop();

        // Use the Thread.Join method to block the current thread 
        // until the object's thread terminates.
        workerThread.Join();
        Console.WriteLine("Main thread: worker thread has terminated.");
    }
    // Sample output:
    // Main thread: starting worker thread...
    // Worker thread: terminating gracefully.
    // Main thread: worker thread has terminated.
}

volatile 修饰符添加到 _shouldStop 的声明后,将始终获得相同的结果(类似于前面代码中显示的片段)。With the volatile modifier added to the declaration of _shouldStop in place, you'll always get the same results (similar to the excerpt shown in the preceding code). 但是,如果 _shouldStop 成员上没有该修饰符,则行为是不可预测的。However, without that modifier on the _shouldStop member, the behavior is unpredictable. DoWork 方法可能会优化成员访问,从而导致读取陈旧数据。The DoWork method may optimize the member access, resulting in reading stale data. 鉴于多线程编程的性质,读取陈旧数据的次数是不可预测的。Because of the nature of multi-threaded programming, the number of stale reads is unpredictable. 不同的程序运行会产生一些不同的结果。Different runs of the program will produce somewhat different results.

C# 语言规范C# language specification

有关详细信息,请参阅 C# 语言规范For more information, see the C# Language Specification. 该语言规范是 C# 语法和用法的权威资料。The language specification is the definitive source for C# syntax and usage.

请参阅See also