.NET 환경에서 작업을 하다보면 UI Thread 와 다른 작업 (예를 들면 Socket 통신 등, …) 에서 생성된 Thread 간에 처리 결과를 다시 UI 의 컨트롤에 설정해야 하는 상황이 많이 발생한다.
지금도 UI 에서 버튼을 누른 후에 통신 구간을 (비동기 Thread 처리) 다녀와서 통신의 결과를 다시 UI의 컨트롤에 보여주어야 하는 상황이다.
이런 경우는 Thread 를 넘나드는 것이기 때문에 Cross - Threading Exception이 발생하게 된다.
물론 이런 경우를 해결하기 위한 아주 단순 무식한 방법으로 Cross - Threading Exception을 검사하지 않도록 하는 설정으로 다음과 같이 처리하면 된다.
- Control.CheckForIllegalCrossThreadCalls = false;
이 방법을 통해서 Exception은 발생하지 않고 정상적으로 동작하는 것을 확인할 수 있지만, 이 방법은 기존의 .NET Framework 1.1 처럼 동작하는 것이기 때문에 권장하는 방법은 아니다.
MSDN에서 권장하는 방법은 Invoke 나 BackgroundWorker를 호출하여 해결하는 방법이다.
문제는 invoke를 위해서는 따로 delegate를 선언해서 처리를 해야 하고, BackgroundWorker는 다중 Threading 처리 시에 적용하는 것이다.
[ Invoke를 이용해서 처리하는 간단한(?) 방법 ]
this.Invoke(new MethodInvoker(
delegate() {
// 컨트롤에 처리할 값 설정
}
));
위의 같이 Windows Forms 에서 제공하는 MethodInvoker와 익명 Delegate를 이용해서 Thread Safe 방식으로 처리가 가능하다.
그런데 문제가 될 수 있는 부분이 해당 처리가 Cross Thread 상태에서 호출이 된 것인지? 아니면 그냥 동일 Thread 상에서 호출된 것인지를 모른다는 문제가 있다.
그렇다고 이런 경우와 저런 경우를 모두 따져서 처리할 수 없기 때문에 아래와 같이 처리할 대상 컨트롤을 통해서 호출 상태를 확인하고 처리하는 코드를 작성하면 된다.
[ 최종 처리 방법 ]
// lbResult는 UI 에 존재하는 ListBox 컨트롤이다.
if (this.lbResult.InvokeRequired) {
this.lbResult.Invoke(new MethodInvoker(
delegate() {
this.lbResult.Items.Add(@"\n[Notice] Connectiong to server.");
}
));
} else
this.lbResult.Items.Add(@"\n[Notice] Connectiong to server.");
댓글
댓글 쓰기