C# - volatile 키워드로 인한 차이점을 발생시키는 예제
이전에 C++ 언어로 만든 volatile 예제를 실었는데요.
C++ volatile 키워드
; https://www.sysnet.pe.kr/2/0/413
아쉽게도 위의 예제를 C#으로 옮겨서 테스트해보면 volatile 유무에 따른 실행차이가 나지 않습니다. 그래도 ^^ 혹시나 싶어, 위의 C++ 예제를 살짝 변경해 다음과 같이 작성해 보니 차이점이 발생하긴 했습니다.
using System;
using System.Threading;
public class TestClass
{
bool m_resultState;
bool m_terminate;
public void Start()
{
int k = 0;
while (m_terminate == false)
{
Console.WriteLine(k++);
Thread.Sleep(1000);
}
m_resultState = true;
Console.WriteLine("m_resultState == " + m_resultState);
}
public void endThread()
{
m_terminate = true;
while (true)
{
if (true == m_resultState)
{
Console.WriteLine("result() == true");
break;
}
}
}
}
public class WorkerThreadExample
{
static void Main()
{
TestClass testClass = new TestClass();
Thread t1 = new Thread(testClass.Start);
t1.Start();
Thread.Sleep(2000);
testClass.endThread();
}
}
위의 프로그램을 Release 모드로 컴파일해 실행하면 화면에 다음과 같이 출력한 후,
0
1
m_resultState == True
무한루프에 빠져 CPU 사용량이 "1/코어"만큼 올라갑니다. 코드를 살짝 보면, "m_resultState == True" 출력은 t1 스레드가 종료하기 바로 전이므로 t1 스레드는 무조건 없어졌다고 확신할 수 있고 출력 내용처럼 m_resultState 필드의 값은 True가 된 것이 맞습니다. 그런데도 endThread 메서드 내부의 result() 메서드는 (분명 이상하지만!) false를 반환하고 있기 때문에 무한 루프에 빠진 것입니다. (result 메서드는 최적화 과정에서 인라인화되었을 것입니다.)
반면 Debug 모드로 컴파일하거나, m_resultState 필드를 다음과 같이 volatile 예약어로 장식해주면 무한 루프 현상없이 프로그램이 잘 종료됩니다.
volatile bool m_resultState;
왜냐하면, volatile로 지정된 필드는 1) 최적화 대상에서 제외하며 2) 해당 값을 읽고/쓰는 코드에 대해 무조건 메모리에 직접 읽고/쓰는 동작으로 연결되기 때문입니다.
(
첨부된 파일은 위의 코드를 재현할 수 있는 예제입니다.)
(참고로, 위의 코드는 어느 순간 CLR이 바뀌면 잘 동작할 수도 있습니다.)
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]