336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

우선 Synchronization, 동기화의 의미에 대해 좀 살펴봐야 겠는데,

일단 동기화 라고 하는 것은 멀티스레드와 관련이 있는 단어다. 즉 싱글스레드에서는 동기화라고 하는 개념은 없다고 생각하자.

 

그럼 멀티스레드에서 동기화가 의미하는 바는, 어떤 코드의 구역이 여러 스레드에 의해 동시에 실행되지 않도록 하는 것이라 할 수 있다.

 

특정 변수에 동시에 접근하지 않도록 하는 것이 동기화 아니냐고 반문할 수도 있겠지만, 결국 특정 변수에 접근한다는 말 자체가 어떤 코드의 실행을 의미하기 때문에, 좀더 일반적인 설명은 특정 코드의 구역에 대한 동시 실행을 막는다는 것이 좋을 듯 하다.

 

위의 동기화 구현은 보통 Lock이라는 요소를 등장시켜 구현한다. 닷넷의 Monitor나 자바의 synchronized 키워드 같은 것들이 다 Lock 개념을 이용한 동기화 구현체다.

 

누구나 알고 있는 너무 당연한 이야기를 장황하게 언급한 이유는,

SynchronizationContext 가 추구하는 동기화와 차이가 있기 때문이다.

 

위에서 이야기한 동기화에서는, Lock으로 묶이는 코드의 구역이 어떤 Thread에 종속되는 것은 아니다.

즉 여러 Thread가 동시에 실행되지 못하게 할 뿐이지, 특정 Thread만 그 코드를 실행할 수 있도록 하는 것은 아니라는 말이다.

 

그런데 만약, 이렇게 동시에 실행되면 안되는 코드의 구역이 여러 곳에 분산되어 아주 많아지는 경우라면 어떤가?

일일이 코드가 동시에 실행되면 안되는지 분석하고, 그 곳을 항상 Lock으로 묶어야 한다. 코드가 점점 커짐에 따라 상황은 점점 복잡해지고 악화되고 버그도 함께 증가할 것이다. 특히 멀티스레드의 버그는 잡기 어렵기로 유명하다.

뭔가 다른 대책이 필요하다.

 

그럼 이렇게 생각해 보자. 차라리 어떤 코드 혹은 객체를 특정 Thread와 묶어 버리는 것이다. 즉 특정 코드 혹은 객체는 항상 특정 Thread만 실행할 수 있도록 하자는 것이다. 이렇게 정하고 나면, 여러 Thread가 동시에 코드 혹은 객체를 접근하지 않는다는 보장이 생기기 때문에, 멀티스레드에 대한 고려를 생각하지 않아도 된다.

코드 혹은 객체를 프로그래밍할 때도, 코드가 실행되는 시작부분(보통 함수나 메소드의 시작부분)에서만 자신을 실행하려고 하는 Thread가 자신이 소속된 Thread인지 검사하는 코드를 넣어주면 되기 때문에, 복잡한 코드의 분석이나 Lock으로 묶어야 하는 부분을 찾지 않아도 된다. 따라서 버그도 줄어들게 된다.

이것은 COM에서 STA(Single-Threaded Apartment)와 같은 개념이다.

 

이렇게 하면 결국 한가지 문제만 해결하면 된다. 다른 Thread에서 그 코드 혹은 객체에 접근하는 방법말이다.

예상하겠지만, 이를 위한 도구가 바로 SynchronizationContext 다.

 

어떤 Thread에 종속된 객체를 접근하고 싶으면, 그 객체가 소속된 Thread의 SynchronizationContext 를 얻어 와서 SynchronizationContext.Post 혹은 SynchronizationContext.Send 를 사용하면 된다.

그러면 Post 혹은 Send 에 넣어준 delegate를 해당 Thread에서 실행되도록 해 준다.

 

일반적으로 이렇게 객체와 Thread를 커플링 시키는 경우는 대부분이 GUI 관련 객체들이다. GUI 관련 객체들은 그 객체를 생성한 Thread와 종속되고, 그 GUI 관련 객체의 조작은 항상 그 객체를 생성한 Thread를 통하도록 되어 있다.

 

닷넷에는 2개의 GUI 관련 프레엠워크가 있는데, WinForm 과 WPF 다.

그리고 이 WinForm 과 WPF 를 위한 SynchronizationContext 가 있는데,

 

System.Windows.Forms.WindowsFormsSynchronizationContext 와

System.Windows.Threading.DispatcherSynchronizationContext 다.

 

둘다 System.Threading.SynchronizationContext 를 상속 받았다.

 

다음 글에서 좀더 이 3개의 클래스에 대해 좀더 자세히 살펴보자.


출처 : http://blog.naver.com/jjoommnn/130034645700

Posted by 역시인생한방
,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

앞선 글에 이어 SynchronizationContext 에 관해서 좀더 이야기 해 보자.

 

이제까지 코드 혹은 객체와 Thread를 커플링 시키는 방식으로 동기화를 구현하는 것에 관해서 이야기 했는데, 여기서 한가지 필수적인 메커니즘을 빼먹은 것 같다.

 

Thread에 종속된 객체는 그 Thread에서만 접근할 수 있고, 따라서 그 객체에 접근하기 위해서는 SynchronizationContext 를 사용해야 한다고 했다. 따라서 SynchronizationContext 는 그 Thread에게, 이 delegate를 실행시켜 달라고 요청하는 도구라고 볼 수 있다.

그렇다면 결국 그 객체가 종속된 Thread는, 요청을 받아 들이고 처리하는 메커니즘을 구현하고 있어야 한다.

 

여러가지 방법이 있을 수 있겠지만 윈도우 운영체제에서는 대부분 메세지 기반(Message Driven), 메세지 펌프로 구현된다.

앞선 글에서도 말했지만 객체와 Thread의 종속은 대부분 GUI와 관련된 경우가 많고, 윈도우 운영체제에서는 GUI와 관련해서 거의 항상 메세지 펌프가 작동하기 때문에, 이를 이용한 SynchronizationContext 는 궁합이 잘 맞는다고 할 수 있다.


이를 위해 WinForm도 그렇고 WPF에서도 실행 요청을 위한 메세지를 하나 정의(RegisterWindowMessage)해서 사용하고 있다.

 

다시 본론으로 돌아와서,

닷넷에서 볼 수 있는 SynchronizationContext 는 3가지가 있다.

 

System.Threading.SynchronizationContext

     |

     +- System.Windows.Forms.WindowsFormsSynchronizationContext

     |

     +- System.Windows.Threading.DispatcherSynchronizationContext

 

일단 SynchronizationContext 는 다른 2개의 부모 클래스인데,

MSDN의 설명으로나, Reflector 를 이용해서 소스를 보더라도, SynchronizationContext 클래스는 실제로 동기화를 수행하지 않는다.

이 SynchronizationContext 의 Post를 호출하면 그냥 ThreadPool을 이용하여 delegate를 실행해 버린다. 당연히 위에서 설명한 동기화 처리가 될리가 없다.(더군다나 SynchronizationContext는 Abstract 클래스도 아니라서 그냥 생성해서 사용할 수도 있다.)

 

이쯤되면 SynchronizationContext의 존재이유에 대해서 의문이 생기기도 하는데,

닷넷에서 모든 Thread는 자신을 위한 SynchronizationContext를 가지고 있다.

하지만 딱히 동기화를 해야 하는 객체를 소유하지 않는 일반 Thread인 경우에는 동기화를 구현할 필요가 없다. 이런 Thread는 SynchronizationContext를 가지게 된다. 뭐 디폴트 SynchronizationContext라고 생각할 수 있다.

'딱히 동기화를 할 필요없는 경우에 사용하는 동기화 도구' 라고 할 수 있는 좀 아이러니 한 상황을 위해서 말이다.

 

앞서, 특별하게 동기화를 통한 보호를 받아야 하는 경우는 GUI 관련 객체들이고, 닷넷에는 2개의 GUI 프레임워크가 있는데, WinForm 과 WPF 라고 이야기 했다.

각각을 위한 SynchronizationContext 가 WindowsFormsSynchronizationContext 와 DispatcherSynchronizationContext 다.

 

위에서 이야기 한 것 중에, 모든 Thread는 SynchronizationContext를 가진다고 했고, 디폴트로는 동기화 기능이 없는 SynchronizationContext가 사용된다고 했다. 그럼 WindowsFormsSynchronizationContext 나 DispatcherSynchronizationContext 는 언제, 어떻게 사용되는 것일까?

 

Thread를 생성할 때, 이 Thread는 WinForm GUI를 위한 Thread, 이 Thread는 WPF GUI를 위한 Thread라고 따로 생성하는 건 아니다.

또한 일반적인 용도로 생성된 Thread가 GUI 용 Thread로 바뀌는 경우도 있을 수 있다.

힌트는 서두에 밝힌 실행요청 메커니즘에 있다. 객체를 소유한 Thread가 실행 요청을 받기 위해서는 메세지 루프를 가져야 한다는 사실 말이다.

 

WinForm도 그렇고 WPF 에서도 그렇고,

WinForm용 메세지 루프로 진입하는 부분, 혹은 WPF 용 메세지 루프(Dispatcher.PushFrame)로 진입하는 부분에서, 현재 루프를 실행하는 CurrentThread에 대해, WindowsFormsSynchronizationContext 혹은 DispatcherSynchronizationContext 를 세팅하도록 되어 있다.

메세지 루프로 진입한다는 이야기는 이제부터 실행요청을 받아 들일 수 있는 상태가 되기 때문이다.

그렇기 때문에 메세지 루프를 빠져나올 때는 CurrentThread에 대해 이전 SynchronizationContext를 복구하도록 되어 있다. 메세지 루프를 빠져 나온다는 것은 더이상 실행요청을 받아들이지 못한다는 의미가 되기 때문이다.

 

그리고 DispatcherSynchronizationContext 는 Dispatcher.Invoke를 이용하여 구현되어 있다.

WPF에는 이미 객체와 Thread의 종속관계를 명확히 하면서, 다른 Thread에서 객체를 접근하는 방법으로 이미 Dispatcher의 Invoke를 마련해 놓았다. 이건 SynchronizationContext가 추구하는 동기화와 정확하게 일치한다.

따라서 DispatcherSynchronizationContext 가 Dispatcher.Invoke를 이용하여 구현되는건 필연적이다.


출처 : http://blog.naver.com/jjoommnn/130034675385

Posted by 역시인생한방
,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

SYSTEM_INFO lpSystemInfo;

 

GetSystemInfolpSystemInfo );

 

lpSystemInfo.dwNumberOfProcessors * 2 + 2

 

이 숫자가 적당하다는 얘기지 최적이란 얘기는 아니다!

'Programming > Network' 카테고리의 다른 글

공인 IP / 사설 IP  (0) 2015.02.07
"온라인 게임서버 프로그래밍 벤치마크" 초간단 정리  (0) 2015.02.07
OSI 7 Layer & TCP/IP 4 Layer  (0) 2015.02.07
Nagle Algorithm  (0) 2015.02.07
서버 프로그래밍시 주의점  (0) 2015.02.07
Posted by 역시인생한방
,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

.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에서 SendMessagePostMessage 생각하면 된다. 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 메서드를 호출하여 작업을 완료한다.


출처 : http://kworks.tistory.com/119

'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
Posted by 역시인생한방
,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

WPF에서는 메인스레드에서 생성한 컨트롤에 다른 스레드가 접근하지 못하도록 되어있습니다.

 

접근하려고 하면 다음과 같은 에러메시지에 직면하죠 :

다른 스레드가 이 개체를 소유하고 있어 호출한 스레드가 해당 개체에 액세스할 수 없습니다.”

 

Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate

{

    lblStatus.Content = "동작중"; // 해당 소스

}));

 

다음과 같이 메인 Dispatcher를 통해 라벨내용을 변경시켜주시면 문제없이 돌아갑니다.


출처 : http://inasie.tistory.com/16

Posted by 역시인생한방
,