Creative Commons License

Microsoft .NET

닷넷!시작하기
닷넷! Ver 2.0~
닷넷!스킬업
웹개발
윈폼개발
실용모듈개발
Tip & Tech
하루 한 문법

Microsoft .NET 개발자들을 위한 공간입니다. 기초강의에서 부터 고급 기술 정보 및 팁등을 다루도록 하겠습니다.

.

닷넷!스킬업

닷넷 기술을 조금 더 깊이 다루고자 합니다. 특정 주제를 정하지 않고 이슈 발생 시 마다 체계적으로 정리하여 공유하겠습니다. 이전 자료를 옮겨온 곳이기도 합니다.

[Thread][동기화] Interlocked 클래스 와 lock 문

작성자 : 박종명
최초 작성일 : 2008-06-16 (월요일)
최종 수정일 : 2008-06-16 (월요일)
조회 수 : 2846

앞서 살펴 보았던 Monitor 클래스 이외에도 닷넷에서는 Thread 간의 동기화를 위한 유용한 툴들을 제공한다.

 

 

* Interlocked 클래스

 

역시 System.Threading 네임스페이스에 있는 이 클래스는 Thread 간에 공유되는 변수에 대한 안전한 접근을 지원한다. 이런 공유 자원에 대한 연산을 Atomic Operation 이라 한다.

원자적으로 변수에 대한 연산을 수행한다는 뜻으로 하나의 Thread 가 공유변수에 대한 연산을 수행할 때 다른
Thread
그 변수에 어떠한 개입도 하지 않는다는 의미로 해석될 수 있겠다.

 

다음과 같이 Thread 간 공유되는 변수가 있다고 가정하자.

 

이렇게 공유되는 변수를 count (수형) 이라 하고 여러 Thread 들은 이 변수의 값을 얻어와서 1 더하고 다시 저장한다고 가정하자. 즉 여러 Thread 가 이 Count 변수를 공유하고 값을 변경하는 멀티Threading 환경인 것이다.

그런데 다음과 같은 상황을 생각해 보자.

Thread 가 수행되는 함수에는 다음과 같은 코드가 있다.

 

public void ThreadMethod(){

            

             count = count + 1;

            

}

 

, 저장되어 있는 count 를 불러와서 1 더하고 다시 count 로 저장하는 코드 블록이다.

 

이 코드는 다음과 같은 순서로 수행된다.

기존의 count 값을 얻어와서 +1 하고 다시 count 로 더한 값을 저장시킨다.

우측의 연산식이 먼저 수행되고 좌측으로 대입되는 순서인 것이다.

 

ThreadMethod 메서드는 여러 Thread 에서 동시에 호출되는 멀티 Thread 환경인 것이다.

이 공유변수의 접근과 연산을 Thread 간 동기적으로 처리 하지 않는다면 다음과 같은 시나리오로 빠져버릴 수 있다.

 

Count 초기값 : 1

 

: Thread1 이 먼저 실행되어 count 값을 조회 한다. 이때 count 의 값이 1 이었다

: Thread2 가 다시 실행권을 가지며 count 값을 조회한다. 이때 역시 count 값은 1이다.

: Thread2 count + 1 하여 count 에 저장한다. Count 2가 된다

: Thread1이 다시 실행권을 가져서 count + 1 한다그러나 Thread1 이 가진 count 값은 2가 아니라

     1 이었다. 따라서 이 과정을 마치면 count 는 역시 2가 된.

 

결국 두 Thread count 공유변수를 1씩 더하면 결과는 3이 되어야 하는데 중간 Thread 실행제어 순서에 의해 count 결과 값이 1이 되어버리는 요상한 결과가 발생한 것이다.

만일 TV 방송에서 자주 하는 불우이웃 성금모금을 이런 멀티 Thread 환경으로 구축했다면 누적된 금액은 실제 금액보다 더 작은 엄청난 결과를 초래하게 되는 것이다. 따라서 특정 Thread 가 공유변수에 접근 및 연산을 수행할 때는 다른 Thread 의 변수 접근,연산을 봉쇄 시켜야 한다.

이것이 바로 Thread간 동기화 이며 이 동기화 방법 중 닷넷 프레임웍이 제공하는 Interlocked 클래스가 그 중 하나인 것이다.

 

 

위의 상황을 Interlocked 클래스를 사용하여 동기화 처리해 보자.

 

public void ThreadMethod(){

            

             Interlocked.Increment(ref count);

            

}

 

Interlocked 클래스의 Increment 메서드는 원자 단위 연산으로 지정된 변수를 증가시키고 결과를 저장한다.

즉 하나의 Thread Interlocked.Increment 에 의해 호출될 동안 (값을 조회하고 저장할 동안) 다른 Thread 는 이 변수 접근을 대기하게 된다.

따라서 값의 어긋남 없이 동기적으로 안전하게 변수 값 변화를 보장할 수 있게 되는 것이다. Interlocked 클래스에는 Increment(증가)와 반대로 Decrement(감소) 메서드도 있다. 또한 Exchange 메서드도 있는데 공유변수를 지정한 값으로 (Atomic하게) 변경하는 메서드 이다.

   

 

* lock Statement

 

이전 글에서 Monitor 클래스를 이용한 Thread 동기화에 대해 알아 보았다.

닷넷은 이 Monitor 클래스 대신에 lock 키워드를 제공하여 동기화를 편하게 할 수 있도록 지원한다

 

lock(x){

            

}

 

블록의 시작( {  ) 에서 x 안의 공유 자원들이 고유한 접근을 보장받고 블록의 끝(  } ) 에서 잠금이 풀린다.

즉 블록내의 구역이 Critical Section(임계구역) 이 되는 것이다.

 

이때 x 는 반드시 참조 타입이어야 한다.

앞서 Interlocked 에서 사용한 ThreadMethod 메서드를 lock 문으로 대체하면 다음과 같다.

 

public void ThreadMethod(){

             lock(this){
                          

                           count = count + 1;

                          

             }

}

 

Thread 간에 공유되는 변수 count this 라는 현재 객체에 존재하는 변수이다. 말했다시피 x 는 참조 타입이어야 하므로 lock(count) 라고 할 수 없다.

 

만일 A 라는 객체의 자원에 대한 동기화 라면 lock(A){…} 라고 할 수 있을 것 이다.

그러나 이 경우 count 는 값 타입이기 때문에 이 변수가 위치한 객체, this 가 사용된 것이다.

 

결국 말로 풀어보면 this 라는 객체의 count 변수에 대한 Thread 간 동기화를 보장하는 것이다.

 

그러나 만일 이 count static 로 선언된 변수라면 예기는 달라진다. Static 변수는 this 로 인식할 수 없기 때문에 다른 방법으로 처리 해야 한다. 이 경우에는 static 변수인 count 가 위치한 클래스의 타입객체를 생성하여 사용하면 된다. 만일 count Test 클래스의 static 멤버라면

 

lock(typeof(Test)) {… count++ … } 라고 하면 된다.

 

마지막으로

 

Lock(x) { … }

 

문장은

 

System.Threading.Monitor.Enter(x);

try{…}

finally{ System.Threading.Monitor.Exit(x); }

 

문장과 완전히 동일하다.

 

이름
비밀번호
홈페이지
OP <- 왼쪽의 문자를 오른쪽 박스에 똑같이 입력해 주세요