다음 코드를 살펴보자.
//static: 모든 쓰레드가 공유함.
static bool _stop = false;
static void ThreadMain()
{
Console.WriteLine("쓰레드 시작");
while (_stop == false)
{
//stop신호를 기다림
}
Console.WriteLine("쓰레드 끝");
}
static void Main(string[] args)
{
Task t = new Task(ThreadMain);
t.Start();
Thread.Sleep(1000);
_stop = true;
Console.WriteLine("Stop 호출");
Console.WriteLine("종료 대기");
t.Wait();//Thread join과 같음
Console.WriteLine("종료");
}
}
ThreadMain을 실행하는 Task로 쓰레드를 만든 다음, 1초 대기 후 _stop 변수를 true로 바꾸어 무한 루프를 멈춘 다음 종료하는 코드이다. 실제로도 우리가 의도한 대로 잘 돌아간다. 그러나 디버그 모드에서 릴리즈 모드로 변환 후 실행시 의도적으로 실행되지 않는 현상이 발생한다. 이유인 즉슨
while(_stop==false){
}//기존 우리가 작성한 코드를
if(_stop==false){
while(true){
}
}//컴파일러가 다음과 같이 바꾸었기 때문.
...이라고 한다. 실제로 두 코드는 논리 상으론 정확하다. 다만 컴파일러가 멀티 쓰레드 환경임을 인지 못하고 멋대로 최적화하다가 오류가 났을 뿐.
이를 간단하게 해결하려면
volatile static bool _stop=false
로 _stop 변수 앞에 volatile를 붙여주면 된다. Release 모드 시 최적화를 하지 말라는 뜻으로 알면 될 듯하다.
volatile를 이용하는 방법 자체보다는 Debug 모드일 때와 Release 모드일 때 멀티쓰레드 환경에선 이러한 이유 때문에 오류가 날 수 있다는 점을 배운 시간이였다.