※ 본 아티클은 CMP MEDIA LLC와의 라이선스 계약에 의해 국문으로 제공됩니다.
멀티 스레드 아키텍처 프로그래밍: 연동 연산
1. 소개 연동 연산은 여러 스레드가 공유하는 변수에 대한 액세스를 동기화하기 위한 간단한 방법을 제공한다. 연동 연산은 임계 영역(critical section)이나 뮤텍스(mutex) 객체와 같은 이전의 동기화 함수를 대체하는 것이 아니라 매우 한정된 요구를 충족하여 동기화 함수를 보완한다.
2. 연동 연산이란? 연동 연산은 정수 크기 또는 포인터 크기 변수를 자동적인 방법으로 업데이트하는 고성능의 방법이다. 연동 연산은 운영 체제 레벨의 방식이 아니라 하드웨어 기반의 동기화 기법이기 때문에 고성능이다. 연동 연산은 고유 함수로 구현되며 심지어 경우에 따라 단일 프로세서 명령어로 변환되기도 한다. 연동 연산은 원자형 요소이다. 어떤 작업을 더 이상 분할할 수 없으면 원자형이라 한다. 원자형 쓰기 중에는 쓰기 과정이 끝나지 않은 상태에서 다른 스레드가 그 값을 읽을 수 없다. 마찬가지로 원자형 읽기 중에는 읽기 과정이 끝나지 않은 상태에서 다른 스레드가 그 값을 변경할 수 없다. 작업이 원자형이 아니면 한 스레드가 이전 값의 일부를 읽고 있을 때 다른 스레드가 변수에서 새 값을 쓸 수 있다. 또한 연동 연산의 원자성은 CPU 전체적으로 보장된다. 아래 표는 Windows API에서 사용할 수 있는 연동 연산을 나타낸다. 다른 작업을 제공하는 API도 있을 수 있다. Linux를 실행할 수 있는 일부 아키텍처는 필요한 하드웨어 지원을 제공하지 않기 때문에 Linux API의 사용자 측면에서는 연동 연산이 제공되지 않는다. 커널 측면과 특정 아키텍처에서만 연동 연산을 사용할 수 있다.
3. 연동 연산의 장점 이전의 잠금 방식에 비해 연동 연산은 가장 가볍고 효율적인 동기화 기본체이며, 많은 장점이 있다. 연동 연산은 프로세서 명령어 한 개 또는 여러 개의 형식으로 하드웨어에서 직접 지원된다. 컴파일러 지원은 고유 함수 형식으로 제공된다. 이 구성은 캐시를 사용하기에 매우 적합하다. 명령어 캐시 안에서의 흐름은 연동 연산을 사용해도 아무 지장이 없지만 데이터 캐시는 플랫폼 메모리 모델에 따라 최소 적중 방식을 택할 수 있다. 연동 연산에는 대기 상태가 없다. 뮤텍스 객체 또는 임계 영역을 포착하려고 하면 연동 연산이 즉시 수행되는 동안 다른 스레드는 해당 객체나 섹션이 해제될 때까지 기다려야 할 수 있다. 바로 이 속성이 잠금 없는 프로그래밍의 기본이다. 잠금 없는 프로그래밍은 잠기지 않는 기본체를 이용하여 동기화를 달성하는 모델이다. 영어로는 lockless 또는 lock-free로 쓰며 비차단(non-blocking) 또는 대기 없는(wait-free) 프로그래밍이라고도 한다. 잠금 없는 프로그래밍은 대단히 어렵기 때문에 애플리케이션 전체를 잠금 없는 상태로 만들려고 하면 안 된다. 그 대신 사용 중인 일부 알고리즘을 잠금 없는 상태로 만드는 데 노력을 집중하는 것이 좋다. 유력한 후보는 연결 리스트 [Val95] [Har01] 및 디큐 [ST04]이다.뮤텍스 객체의 경우 커널 모드로 전환하는 사용자 모드는 없다. 사용자 모드를 커널 모드로 전환하는 것은 대부분의 플랫폼에서 매우 느리기 때문에(Pentium 4[Ric05]에서 일반 함수 호출보다 약 100배 더 느림) 이것은 중요한 장점이다. 연동 연산을 사용하여 복잡한 동기화 기본체를 만드는 것은 가능하고 비교적 쉽다. 다음은 _InterlockedCompareExchange 및 _InterlockedExchange를 사용하여 임계 영역API를 기본적으로 구현한 것이다. 다음 구현은 한 예에 불과하다는 것을 명심한다. 매우 특별한 요구가 있는 경우가 아니면 표준 임계 영역 API를 대체하는 기능을 작성하지 말아야 한다..... .............(중략)
* 자세한 내용은 첨부문서(pdf)를 참고하시기 바랍니다.
|