기본 콘텐츠로 건너뛰기

[WinForm] Cross-Threading 문제...

.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.");


댓글