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 크기의 광고 코드만 넣을 수 있습니다.

좀 어렵기는 하지만 Git은 정말 좋은 도구이다. Git을 쓰기 시작하면서 SVN이 얼마나 불편하고 구린지를 이해할 수 있다. 어쨌든 GitHub의 엄청난 성장아래 이제는 대부분의 오프소스 프로젝트들이 GitHub로 이전하면서 회사에서 Git을 사용하지 않더라도 Git을 사용하지 않으면 안되는 때가 왔다. 하지만 Git은 상당히 어려운 도구이고(git 홈페이지에 나온 easy to learn은 홍보성 문구로 거짓말이다. 어렵다!!) 그룹스터디를 할 때 GitHub을 사용하는 경우가 꽤 많았는데 사람들이 숙제를 해도 제출을 못하는 사태가 자주 발생하면서 각각의 명령어에 대한 사용법에 대한 설명도 중요하지만 전체적인 사용방식을 좀 설명할 필요가 있다고 느껴졌다.

내가 생각하기에 사람들이 Git을 이해하는데 어려워하는 부분이 몇가지 있는데

  • GitHub를 설명할 때 Git의 기능과 GitHub의 기능을 명확하게 구분해 주지 않는다.
  • 대부분의 개발자들이 가진 Subversion에 대한 이해가 오히려 Git을 이해하는데 방해가 된다. Git은 DVCS이고 SVN은 VCS이다. 앞에 Distribute가 붙은건 마케팅적으로 괜히 붙힌게 아니라 분산 저장소이기 때문이다. Git에서 이 분산저장소라는 것은 무척 중요하다.

그래서 GitHub을 예시로 fork해서 소스를 수정하고 적용까지 하는 전체적인 흐름 과정을 이해하면 각각의 명령어를 이해하는데 좀더 도움이 되지 않을까 한다. 예제의 설명을 위해서 jQuery에서 어떤 버그를 발견해서 소스를 수정한뒤에 다시 jQuery에 적용요청을 하는 일련의 과정을 예시로 들어보자. git의 각 명령어를 일일이 다 설명하는 것은 내용이 너무 많기 때문에(모르는 명령어도 많고.. ㅡㅡ;;) 흐름을 이해할 수 있는 수준에서만 명령어를 설명할 것이다. 필요하다면 각 명령어는 따로 찾아보고 익혀야 한다.

Github 흐름 다이어그램


이 과정은 도식화 하면 위처럼 된다. 좀 복잡해 보일 수 있는데 하나씩 살펴보자.


Fork 
GitHub의 저장소를 보면 다음 화면처럼 3가지의 저장소 주소를 제공하고 있다.(Git에서 여러가지 프로토콜을 사용해서 저장소를 열어줄 수 있지만 GitHub가 제공하는 저장소가 이렇다.)

jQuery git 저장소의 주소 화면


jQuery 저장소에는 쓰기 권한을 가지고 있지 않으므로(아무나 쓰기를 할 수 있다면 저장소는 당연히 엉망일 될 것이다.) 우측에 보듯이 Read-Only 권한만 있음을 알 수 있다. 만약에 지금 시나리오처럼 소스를 수정해서 적용할 것이 아니고 그냥 혼자 소스를 살펴보기만 할 것이라면 이 주소를 사용해서 git clone를 하면 로컬에 저장소를 내려받을 수 있다. 하지만 우리는 소스를 수정할 수 있는 저장소를 관리해야 하므로 Fork를 해야 한다. 저장소 관리자와 친분이 있다면 요청을 해서 해당 저장소에 Push할 수 있는 권한을 받을 수도 있겠지만 일반적으로는 Fork한 뒤에 나중에 Pull Request하는 방식으로 진행이 된다.

저장소를 fork하는


앞에서 본 다이어그램에서 위의 부분이다. jQuery의 저장소를 Fork받아서 내 저장소로 복사본을 만든다. 저장소의 우측상단을 보면 다음처런 Fork버튼을 볼 수 있다.

Github의 fork


이 Fork버튼을 누르면 jQuery 저장소의 지금 상태 그대로를 복사해서 자신의 GitHub계정에 jQuery 저장소를 생성한다. 이 Fork는 git의 기능이 아니라 GitHub가 git의 기능을 추상화해서 제공하는 기능이므로 git fork같은 명령어는 없다. 간단히 생각하면 git clone을 GitHub내에서 진행했다고 생각하면 된다.(내부 구현은 알 수 없지만....)

fork로 생성된 Github 저장소 화면


이제 자신의 계정에 jQuery저장소가 생겼고 저장소 주소에 Read+Write 권한이 있는 것을 볼 수 있다. 이제 이 저장소에는 소스를 수정해서 푸시를 할 수 있다. 이 저장소는 jQuery의 원래 저장소와 완전히 동일한(주소만 다른) 저장소이다. 분산저장소이기 때문에 저장소가 또 하나 생긴 것이고 다른 사람이 jQuery 원래 저장소 대신 내 저장소를 똑같이 Fork 받아서 수정하는 것도 당연히 가능하다 각 저장소는 모두 권한외에는 모두 동일한 기능을 가진다.


Clone
원격에서는 소스를 수정할 수 없으므로 이 저장소를 작업할 로컬 머신에 내려받아야 하는데 이 과정이 Clone이다.

Github 저장소를 Clone받는 다이어그램


Clone는 git을 잘 몰라도 대부분 알고 있는 git clone git@github.com:outsideris/jquery.git 명령어로 수행한다. SSH 주소를 사용한 것은 git 프로토콜이 HTTPS보다 훨씬 빠르고 GitHub에 SSH키를 등록해 놓으면 푸시할때 암호를 입력하지 않아도 되기 때문이다. 

git clone하는 화면


Clone을 받아오면 로컬에 jquery 폴더가 생기고 jquery 폴더안에 git 저장소를 내려받은 것을 볼 수 있다. 저장소 이름이 jquery이기 때문에 jquery 폴더가 생겼고 다름 폴더명을 사용하려면 git clone git@github.com:outsideris/jquery.git NEW_NAME과 같이 이름을 지정하면 된다. Fork가 GitHub내에서 저장소를 복사한 것이라면 clone은 원격 저장소를 로컬로 복사한 것이다.


Commit
이제 저장소를 로컬에 가져왔으므로 소스를 수정하는 작업을 해야한다. git에서는 관례적으로 메인 브랜치로 master 브랜치를 사용하지만 필요하다면 다른 브랜치를 메인으로 사용해도 아무런 문제가 없다. master는 그냥 관례적으로 약속한 브랜치일 뿐이다. 

로컬에서 git 저장소를 커밋하는


jQuery의 소스를 수정하기 위해서 master  브랜치를 수정해야 하는데 Subversion과는 다르게 Git에서는 브랜치를 생성하는 것을 권장하고 있고 일반적으로 master 브랜치에서 다른 브랜치를 생성해서 작업하는 것이 일반적이다. 여기서는 patched라는 브랜치를 생성한다.

사용자 삽입 이미지


git branch 명령어를 사용해서 현 브랜치에서 새로운 브랜치를 생성하고 해당 브랜치로 사용하는 브랜치를 바꾸었다. 여기서 hotfixes/patched라고 브랜치를 생성한 이유는 git-flow의 관례이고 그냥 브랜치명이 hotfixes/patched라고 지은것이고 계층적으로 구분하기 위해서 생성했다고 보면 된다. 위의 두 과정대신 git checkout -b hotfixes/patched를 사용하면 명령어 하나로 브랜치를 생성해서 바로 이동까지 할 수 있다. 사실 git을 사용하는 대부분의 과정은 이 단계에서 이루어지는데 기본적으로 소스를 수정하고 커밋할 소스를 git add한 후에 git commit을 한다. commit은 현재의 git 저장소에 소스를 적용해서 히스토리를 남긴 것으로 SVN의 commit과 다르게 원격저장소에 적용되는 것은 아니다.


출처 : http://blog.outsider.ne.kr/865


Posted by 역시인생한방
,