릴리즈 모드 시 발생하는 코드 최적화에 의한 오류를 공부해보자

아래 코드는 멀티 쓰레드 환경에서 주 쓰레드를 1초 동안 멈추었다가 다시 동작하게 하여 다른 쓰레드를 종료하게 만드는 코드이다.

   class Program
    {
       	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); // 밀리세컨드 단위 동안 잠든다 (대기)
            Console.WriteLine("1초가 지났습니다.");

            _stop = true;

            Console.WriteLine("Stop 호출");
            Console.WriteLine("종료 대기 중");

            t.Wait(); // <==> Thread.Join() 
            Console.WriteLine("종료 성공");
        }
       
    }

1초가 지난 후에 _stop이 true로 변경되어 Task(Mainthread)가 종료되고 이어서 주 쓰레드 역시 종료된다.

하지만 Debug 모드에서와 달리, Release 모드에서는 동작이 달라지게 된다.

stop이 호출되었다는 뜻은 _stop이 true로 변경되었다는 뜻인데 Task가 종료되지 않는 것이 이상하다.

이는 Release 모드 시, 코드 최적화가 일어나서

while(_stop == false) {}  부분이 

if(_stop == false) {
	while(true){}
}
처럼 동작하기 때문이다. 

컴파일러는 while의 본문에 _stop을 변경하는 코드가 없는 것을 고려하여 코드를 최적화 하였지만, 멀티 쓰레드 환경임을 고려하짐 못하여 위와 같은 에러가 발생하는 것이다.

이를 막기 위해서는 Release 모드 시 최적화를 하지 말라는 것을 알려주는 키워드가 필요하다.

volatile static bool _stop = false 라고 처음에 선언한다. 

volatile 키워드를 붙이면 Release 모드 시 최적화를 하지 말라고 컴파일러에게 알려줄 수 있다.

하지만 volatile은 C#에서 기구한 동작을 하기 때문에 C# 전문가들이 사용하지 말라고 권고하고 있다.

profile
POSTECH EE 18 / Living every minute of LIFE

0개의 댓글