.NET 프로그래밍을 하는 데에 있어 한가지 장점을 꼽으라면 전에 비해 상당히 쉬워진 멀티쓰레드 프로그래밍이라고 할 수 있다. 하지만 많은 개발자들이 놓치는 부분이 쓰레드에서 UI를 접근하는 부분이다.
우선 윈도우즈 프로그래밍에서 UI부분이 어떻게 동작하는지 이해할 필요가 있다. 윈도우에서 UI는 메시지 펌프 (Message Pump)라고 불리는 방법에 의해서 화면에 그려진다. 선하나를 화면에 그린다고 가정하면, 윈도우즈는 그 선을 계속해서 반복적으로 그림으로써 사용자에게 마치 선이 하나가 있는 것처럼 보이게 하는 것이다. 그리고 이를 위해 수 많은 메시지, 즉 인스트럭션이 보내진다.
예를 들어 폼의 이벤트를 살펴보면 OnPaint라는 이벤트를 발견할 수 있다. 이 이벤트내에 int I = 0; 이라는 코드를 삽입하고 브레이크 포인트를 걸어 실행을 시켜보면 윈도우는 보이지 않고 이 브레이크 포인트가 계속 해서 걸리는 것을 알 수 있다. 사용자가 모르는 사이 .NET 프레임웍은 윈도우즈에 해당 UI를 화면에 그리도록 명령을 끊임 없이 보내며 이 이벤트를 발생시키는 것이다.
여기서 한가지 중요한 부분이 있다. .NET 프레임웍은 윈도우즈에 메시지를 보내는 과정에서 이벤트를 발생 시킴으로써 개발자에게자신의 코드를 삽입할 기회를 부여한다는 것이다. 이 모든 부분이 UI에 접근하려는 쓰레드와 관련이 있다.
모든 프로그램은 기본적으로 하나의 쓰레드로 시작이 된다. 따라서 폼을 화면에 그리는 메시지와 이벤트들도 그 쓰레드 안에서 구동이 된다. 하지만 사용자가 시작한 쓰레드는 이 쓰레드와는 별개로 실행이 된다. 따라서 이 커스텀 쓰레드에서 UI에 직접 접근을 하면적절한 마샬링 없이 다른 쓰레드를 침범하는 것이다 (Cross Thread). 다시 말해, UI 쓰레드가 열심히 화면에 폼을 그리고 있는데갑자기 다른 쓰레드가 와서 딴 짓을 하고 가는 꼴이 되버리는 것이다.
이를 위해서 UI 컨트롤들은 Invoke, BeginInvoke 메서드와 InvokeRequired 속성을 지원한다. Invoke 메서드는 동기(Synchronous) 메서드이고 BeginInvoke는 비동기 (Asynchronous) 메서드이다. 이 메서드들은 컨트롤들이 생성된 쓰레드의 메시지 펌프에 커스텀 코드를 삽입하여 그 쓰레드에서 컨트롤를 업데이트할 수 있도록 한다. Win32에서 SendMessage나PostMessage를 생각하면 된다. InvokeRequired 속성은 Boolean 값을 반환하며 Invoke 나 InvokeRequired 메서드를 호출해야 하는지를 알려준다.
Invoke 와 BeginInvoke 메서드는 인자로서 delegate 형태를 받는다. 다음은 Invoke 메서드를 호출하는 방법중 하나이다.
this.Invoke(new MethodInvoker(UpdateMe));
…
void UpdateMe()
{
…
}
MethodInvoker는 프레임웍에서 지원하는 delegate 클래스로 인자가 없는 메서드들을 호출 할 수 있도록 정의가 되어있다. 만약인자를 넘겨줄 필요가 있다면 delegate 을 따로 정의하여 사용하면 된다. 다음은 인자를 갖는 메서드를 호출할 때의 예이다.
Delegate void UpdateMeDelegate(string message);
…
this.Invoke(new UpdateMeDelegate(UpdateMe), “This is the message”);
…
toid UpdateMe(string message)
{
…
}
Invoke 메서드는 동기 메서드이기 때문에 바로 실행되어 긴 시간이 걸리는 작업에는 적합하지 않다. 이런 경우는 비동기 메서드인BeginInvoke를 사용하면 된다. BeginInvoke 메서드는 EndInvoke 메서드와 짝으로 구동이 된다. EndInvoke 는 비동기로 실행된작업을 완료하는 역할을 한다.
IAsyncResult ar = this.BeginInvoke(new MethodInvoker(UpdateMe));
…
this.EndInvoke(ar);
BeginInvoke 메서드에서 실행된 작업이 끝나면 EndInvoke 메서드를 호출하여 작업을 완료한다.
'Programming > C#' 카테고리의 다른 글
StringFormat 양수(+) / 음수(-) 표시 (0) | 2015.02.05 |
---|---|
#region #endregion (0) | 2015.02.05 |
데이터 타입의 종류와 범위 (0) | 2015.02.04 |
연산자 우선순위 (0) | 2015.02.04 |
C# String Formatting (0) | 2015.02.04 |