Thread를 사용하다 보면 직면하는 문제점이 있다.
프로그램이 종료되더라도 스레드가 여전히 백그라운드에서 동작중이라 완전히 종료되지 않는 문제가 발생하곤 한다.
일반적으로 스레드를 통해 반복적인 작업을 수행하게 되면 do-while 루프 등을 사용하여 내부적으로 무한 루프를 돌리고, 루프의 조건 변수로 bool 변수 등을 지정해서 스레드를 간접적으로 종료시키는 방법을 사용하게 된다. 아래와 같이.
bool isRun;
int count = 0;
void button_Start_Click(object sender, EventArgs e)
{
if(isRun) return; // 이미 루프가 돌고 있는 상태라면 새로운 스레드를 생성하지 않는다.
new Thread(counter).Start();
}
void button_Stop_Click(object sender, EventArgs e)
{
// Stop 버튼을 눌렀을 때, isRun을 false로 만들어 counter의 루프 조건을 거짓으로 만든다.
isRun = false;
}
void counter()
{
isRun = true;
while(isRun)
{
count++;
Thread.Sleep(1000);
}
}
사용자가 X 버튼을 눌러 폼을 닫게 되는 경우에도 스레드를 멈추어 줘야 하기 때문에,
void form1_FormClosing(object sender, FormClosingEventArgs e)
{
isRun = false;
}
이렇게 폼을 닫을 때 발생하는 이벤트에도 isRun을 false로 하는 코드를 추가해야 할 것이다.
문제는 예기치 못한 예외로 인해 프로그램이 갑작스럽게 종료되어 버리는 상황이 있다는 것이다.
물론 발생할 수 있는 모든 예외에 대해 예외 처리를 하는 것이 가장 좋은 방법이겠지만, 예외 처리가 불가능한 상황 또한 생기기 마련이다.
이러한 문제가 있을 때 ThreadPool을 사용하면 스레드가 메인 스레드에 종속적으로 동작하도록 할 수 있다.
bool isRun;
int count = 0;
void button_Start_Click(object sender, EventArgs e)
{
if(isRun) return; // 이미 루프가 돌고 있는 상태라면 새로운 스레드를 생성하지 않는다.
ThreadPool.QueueUserWorkItem(new WaitCallback(counter));
}
void button_Stop_Click(object sender, EventArgs e)
{
// Stop 버튼을 눌렀을 때, isRun을 false로 만들어 counter의 루프 조건을 거짓으로 만든다.
isRun = false;
}
// ThreadPool에 등록될 메서드는 매개변수로 object state가 필요하다!!
void counter(object state)
{
isRun = true;
while(isRun)
{
count++;
Thread.Sleep(1000);
}
}
이렇게 하면 어떠한 상황에서도 메인 스레드가 종료될 경우 ThreadPool에 등록된 스레드들 또한 즉시 강제로 종료된다.
Thread를 종료시키기 위해 Thread.Abort() 메서드를 사용하는 것은 잘못된 방법이다.
Thread.Abort() 메서드는 스레드 내부에서 예외를 발생시켜 중단하는 방법이지 스레드 외부에서 스레드를 중단시키기 적절한 방법이 아니다. 스레드를 안전하게 잘 사용하는 가장 좋은 방법은 발생할 수 있는 예외들에 최대한 대비하고, 스레드 외부에서 스레드 내부의 루프를 중단시킬 수 있는 적절한 방법을 마련하는 것이다.
'.NET > C#' 카테고리의 다른 글
[C#] 속성(Property)이란 무엇인가? (0) | 2021.09.20 |
---|---|
[C#] out 형식 파라미터 사용법 (0) | 2021.08.15 |
[C#] FileInfo 클래스로 파일 정보 확인 (0) | 2021.08.03 |
[C#] StreamReader와 StreamWriter로 파일 읽기, 쓰기 (0) | 2021.07.27 |
[C#] using 구문 사용법 (0) | 2021.07.23 |