영어로 읽기

다음을 통해 공유


volatile(C# 참조)

volatile 키워드는 동시에 실행되는 여러 스레드에 의해 필드가 수정될 수 있음을 나타냅니다. 컴파일러, 런타임 시스템 및 하드웨어는 성능상의 이유로 메모리 위치에 대한 읽기 및 쓰기를 다시 정렬할 수 있습니다. volatile로 선언된 필드는 특정 종류의 최적화에서 제외됩니다. 모든 실행 스레드에서처럼 휘발성 쓰기의 단일 순서가 모두 보장되는 것은 아닙니다. 자세한 내용은 Volatile 클래스를 참조하세요.

참고

다중 프로세서 시스템에서 휘발성 읽기 작업은 프로세서에서 해당 메모리 위치에 쓴 최신 값을 가져오도록 보장하지 않습니다. 마찬가지로, 휘발성 쓰기 작업은 기록된 값이 다른 프로세서에 즉시 표시되도록 보장하지 않습니다.

volatile 키워드는 다음 형식의 필드에 적용될 수 있습니다.

  • 참조 형식.
  • 포인터 형식(안전하지 않은 컨텍스트에서). 포인터 자체는 volatile이 될 수 있지만, 포인터가 가리키는 개체는 volatile이 될 수 없습니다. 즉, "pointer to volatile"을 선언할 수 없습니다.
  • sbyte, byte, short, ushort, int, uint, char, floatbool와 같은 단순 형식.
  • 기본 형식 byte, sbyte, short, ushort, int 또는 uint 중 하나가 있는 enum 형식.
  • 참조 형식으로 알려진 제네릭 형식 매개 변수.
  • IntPtrUIntPtr.

doublelong을 포함한 기타 형식은 해당 형식의 필드에 대한 읽기 및 쓰기가 원자성임을 보장할 수 없기 때문에 volatile로 표시될 수 없습니다. 이러한 형식의 필드에 대한 다중 스레드 액세스를 보호하려면 Interlocked 클래스 멤버를 사용하거나 lock 문을 통해 액세스를 보호합니다.

volatile 키워드는 class 또는 struct의 필드에만 적용할 수 있습니다. 지역 변수는 volatile로 선언할 수 없습니다.

예시

다음 예제에서는 공용 필드 변수를 volatile로 선언하는 방법을 보여 줍니다.

C#
class VolatileTest
{
    public volatile int sharedStorage;

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

다음 예제에서는 보조 또는 작업자 스레드를 만들어 기본 스레드와 병렬로 처리하는 데 사용하는 방법을 보여줍니다. 다중 스레딩에 대한 자세한 내용은 관리되는 스레딩을 참조하세요.

C#
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.
}

_shouldStop의 선언에 volatile 한정자를 추가하면 항상 동일한 결과가 표시됩니다(앞의 코드에 표시된 것과 유사함). 그러나 _shouldStop 멤버의 해당 한정자가 없으면 동작을 예측할 수 없습니다. DoWork 메서드가 멤버 액세스를 최적화할 수 있으므로 부실 데이터를 읽게 됩니다. 다중 스레드 프로그래밍의 특성으로 인해 부실 읽기 수는 예측할 수 없습니다. 프로그램의 실행에 따라 약간 다른 결과가 생성됩니다.

C# 언어 사양

자세한 내용은 C# 언어 사양을 참조하세요. 언어 사양은 C# 구문 및 사용법에 대 한 신뢰할 수 있는 소스 됩니다.

참고 항목