Volatile modifier
Peponi │ 11/27/2024 │ 4m
Volatile modifier
Peponi
1. Introduction
volatile
한정자는 선언 멤버가 사용되는 곳에서 코드 최적화를 하지 말아야 한다는 것을 컴파일러에 알려준다. 선언 멤버를 메모리에서 직접 읽고 쓰게 하고, 원자성은 보장되지 않는 특징을 갖고 있다. C# 전용 한정자로 VB 등에서는 사용할 수 없다.
동일한 기능을 제공하는 요소로 System.Threading.Volatile 클래스가 있다. Volatile
클래스는 Read()
및 Write()
메서드를 제공하여 읽기 및 쓰기 구분이 가능하게 해준다.
2. Example
public class InfiniteLoop
{
public volatile bool Flag = true;
public int Loop = 0;
public void Worker()
{
while (Flag) Loop++;
}
}
3. volatile 한정자가 필요한 경우
보통의 경우 volatile
이 필요하지 않지만, 코드 구성에 따라 키워드가 필요할 수 있다.
위의 예제의 경우 클래스명을 일부러 InfiniteLoop
로 만들었다. Flag
변수에서 volatile
을 제거한 후 코드 최적화를 하도록 컴파일러에 지시하면 멀티쓰레드 환경에서 무한 루프를 발생시킬 수 있다.
public class InfiniteLoop
{
public bool Flag = true;
public int Loop = 0;
public void Worker()
{
while (Flag) Loop++; // 코드 최적화 시 while 루프 탈출 불가
}
}
public class InfiniteLoopExample
{
private static void Main()
{
InfiniteLoop test = new InfiniteLoop();
new Thread(test.Worker).Start();
Thread.Sleep(1000);
test.Flag = false;
Console.WriteLine(test.Loop); // 코드 최적화 시 종료 불가
}
}
상기 코드를 debug
모드로 실행하는 경우 Console 출력 이후 정상적으로 종료된다. 그러나 코드 최적화가 설정되어 있는 debug
또는 release
모드로 변경 시 Console 출력 이후 무한 루프가 발생하게 된다.
이는 코드 최적화 과정에 의해 나타나는 의도치 않은 문제로, MSDN에서는 다음과 같이 소개한다.
멤버 선언에 volatile 한정자를 추가하면 항상 동일한 결과가 표시됩니다. 그러나 멤버에 해당 한정자가 없으면 동작을 예측할 수 없습니다. 메서드가 멤버 액세스를 최적화할 수 있으므로 부실 데이터를 읽게 됩니다. 다중 스레드 프로그래밍의 특성으로 인해 부실 읽기 수는 예측할 수 없습니다. 프로그램의 실행에 따라 약간 다른 결과가 생성됩니다.
코드 최적화에 의해 변경된 클래스는 다음과 유사하게 된다.
public class InfiniteLoop
{
public bool Flag = true;
public int Loop = 0;
public void Worker()
{
if (!Flag) return;
else
{
while (true) Loop++;
}
}
}
위와 같은 변화에 의해 무한 루프가 발생되며, Flag
멤버를 property로 선언하여도 동일하게 발생한다. 따라서, 코드 최적화에 의한 의도치 않은 동작을 방지하기 위해 volatile
한정자를 적절히 활용하는 것이 필요하다.