본문 바로가기

Silverlight

Silverlight UI Thread에 대해서 알아보자.


안녕하세요. 클라인스입니다.

오늘은 Silverlight UI Thread 모델에 대해서 알아보도록 하겠습니다.

많은 프로그램들이 백그라운드로 다수의 스레드를 만들어 일을 처리합니다.

어떤 스레드는 네트워크 통신 작업을 하고 어떤 스레드는 계산하는 작업을 하고~기타 등등등..

이럴 경우 Silverlight에서의 코드는 아래와 같이 구현할 수 있습니다.

[xaml 코드]

Grid안에 단순히 Button과 TextBox를 배치하였습니다.

[cs코드]

버튼 클릭시 Thread를 생성하며 해당 스레드에서는 txtBlock에 문자열을 할당합니다.

[실행결과]

앗..근데 버튼을 눌러 스레드를 생성하여 txtBlock에 문자열을 할당하였는데 아무런 변화가 없습니다. 어찌 된것일까요??

더군다나 IE의 아래쪽을 보니 아래와 같은 에러메시지도 보여줍니다.

[에러메시지 창]

에러메시지를 살펴보니 잘못된 크로스 스레드 액세스라고 나오네요.. 대체 왜 이런 걸까요??

바로 Silverlight의 UI 스레드 모델 때문에 그렇습니다.

Silverlight에서 UI는 그 UI가 속하는 UI 스레드에서만 처리할 수 있습니다.!!

여기서 UI 스레드는 해당 UI를 만들어낸 스레드를 나타냅니다.

즉, UI를 업데이트하는 권한은 해당 UI 컴포넌트를 만들어낸 UI 스레드 하나 뿐입니다.

그런 이유로 저희가 생성한 스레드는 txtBlock의 UI 스레드가 아님에도 불구하고 해당 UI의 업데이트에 참견을 하려고 했고

그로인해 Exception이 발생한 것입니다.

그럼 어찌 해결해야 할까요.. 방법은 업데이트 하려는 UI의 UI 스레드에게..

"이것좀 갱신해주면 안될까??" 하고 정중히 부탁을 하면 됩니다.^^

UI스레드에게 작업을 요청하는 방법은 Dispatcher라는 녀석을 통해서 하게 됩니다.

 

그럼 Dispatcher라는 녀석은 어디서 온 것일까요?? 화성에서 왔나..--a


UserControl에 대한 클래스 상속도 인데요~ 부모 클래스 중에서

DependencyObject를 살펴보면

 

[DependencyObject class]


내부적으로 Dispatcher라는 녀석을 가지고 있네요!! 꼭꼭 숨어있었군요..

 

이 녀석의 멤버에는 Dispatcher.Invoke() 와 Dispatcher.BeginInvoke()가 있습니다. 

두 녀석의 차이는 Dispatcher.Invoke()는 동기 방식이며 Dispatcher.BeginInvoke()는 비동기 방식으로

작업을 요청한다는 것입니다.

Windows Programming에서 SendMessage와 PostMessage 방식의 차이점과 비슷하다고 볼수도 있을것 같습니다.

Dispatcher를 통해 UI스레드에게 작업을 요청하게 되면 UI스레드의 내부 Queue에 작업이 할당되고 처리됩니다.

그럼 코드를 할당하여 수정해보면..아래와 같습니다.

[수정된 코드]

[실행결과]

이제서야 정상적으로 출력이 되네요..^^

이와 관련하여 좋은 예제가 MSDN에 있어 하나더 소개해 드립니다.

위 UI에서 "Start"버튼을 클릭 시 1부터 소수를 찾고 소수를 찾게 되면 해당 숫자로 갱신을 하게 됩니다.

그리고 "Stop" 클릭시 중지하게되고 다시 "Resume" 클릭시 다시 작업을 시작하게 됩니다.

이는 아주 간단한 작업이기는 하지만 소수 검색이 영원히 계속될 경우 약간의 문제가 될 수 있습니다.

 

버튼의 클릭 이벤트 처리기 안에서 전체 검색을 처리할 경우 다른 이벤트를 처리할 수 있는 기회가 UI 스레드에 제공되지 않기 때문에 UI는 입력에 응답하거나 메시지를 처리할 수 없습니다.

 

따라서 다시 그리기를 수행하거나 단추 클릭에 응답하지 않게됩니다.

계산 및 이벤트 처리 간의 처리 시간을 분할할 수 있는 최선의 방법은 <?XML:NAMESPACE PREFIX = MSHelp NS = "http://msdn.microsoft.com/mshelp" /><?xml:namespace prefix = mshelp /><?xml:namespace prefix = mshelp />Dispatcher에서 계산을 관리하는 것입니다.

BeginInvoke 메서드를 사용하면 UI 이벤트를 가져온 동일한 큐에서 소수 검사를 예약할 수 있습니다.

위 예제에서는 단일 소수 검사를 한 번에 하나만 예약합니다.

소수 검사가 완료된 후 다음 검사를 즉시 예약합니다. 이 검사는 보류 중인 UI 이벤트가 처리된 후에만 진행됩니다.

 

 

위 그림을 보시면 UI 스레드큐에 계산작업을 넣어서 처리하는 것을 볼 수 있습니다.

이럴 경우 이벤트 처리도 되고 UI 갱신도 되고 계산도 되고~일석 몇조일까요??^^

 

위에 관한 자세한 내용 및 코드는 MSDN에서 Dispatcher 클래스 [WPF] 를 찾아보시길 바랍니다.^^

 

그럼 수고하세요.

 

감사합니다


[출처] 실버라이트 네이버 카페