다음은 멀티쓰레드 프로그래밍에서 부지런한 프로그래머가 흔히 사용하는 코드의 일부이다.
1 2 3 |
EnterCriticalSection(&cs); // Manipulate some shared data here. LeaveCriticalSection(&cs); |
알다시피 이와 같은 방법은 코드의 수정을 복잡하게 만들고, 데드락을 피하기 위해서 락의 잠금과 해제 쌍을 완벽히 유지해야 하는 부담도 가지고 있다. Exception이나 갑작스런 흐름의 변화는 이러한 부담을 가중시킨다. 결정적으로…, 귀찮다.
1 2 3 4 5 6 7 |
EnterCriticalSection(&cs); if ( ... ) { // Ooops, you should free cs before return. return; } LeaveCriticalSection(&cs); |
그래서 조금 더 게으른 프로그래머는 auto_ptr을 흉내 낸 클래스를 만들어 사용한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class AutoCriticalSection { public: AutoCriticalSection(CRITICAL_SECTION* pCS) : m_pCS(pCS) { EnterCriticalSection(m_pCS); } ~AutoCriticalSection() { LeaveCriticalSection(m_pCS); } private: CRITICAL_SECTION* m_pCS; }; |
크리티컬섹션의 범위가 좁은 경우에는 – 그렇다! 보호해야 하는 것은 데이터이지 함수가 아니다 – AutoCriticalSection타입의 변수의 범위를 제한해 주어야 한다.
1 2 3 4 5 |
// Now you limit protected range as you want. { AutoCriticalSection(&cs) myAutoCS; // Manipulate some shared data here. } |
위 코드는, 그것을 아름답지 못하게 만드는 두 가지 문제점 있다. 첫 번째는, AutoCriticalSection의 변수 명을 사용자가 선택해야 한다는 것이고, 두 번째는 블럭이 의미하는 바를 직관적으로 알아차리기 어렵다는 것이다.
아래는 이를 해결하기위한, 좀 더 많이 게으른 프로그래머의 코드이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
class CriticalSectionContainer { public: CriticalSectionContainer(CRITICAL_SECTION* pCS) : m_pCS(pCS) { EnterCriticalSection(m_pCS); } ~CriticalSectionContainer() { LeaveCriticalSection(m_pCS); } operator bool() { return true; } private: CRITICAL_SECTION* m_pCS; }; #define CSBLOCK(x) if (CriticalSectionContainer __csc = x) |
두 가지 문제점을 개선한 이 코드에는 두 가지 아이디어가 녹아있다.
첫 번째는, 가독성있는 블록을 사용하기 위해서는 기존의 문법에서 방법을 빌린 것이다. 처음에는 이를 위해서 for문을 사용했다. 그러나 loop를 한번만 돌게 하기 위해서 CriticalSectionContainer클래스에 추가적인 변수가 필요했고, 블록 내에서 break와 continue를 사용할 수 있는 어색함이 남게 된다. 사소한 문제지만, 이는 변수 하나에 해당하는 양의 메모리와 한번의 점프 오퍼레이션이 소모된다. 그래서 if문을 사용했고, if문에서 참, 거짓을 판단하기 위해서 bool 연산자 오버로딩을 사용한 것이 두 번째 아이디어다.
다음은 이를 어떻게 사용하는지 보여준다.
1 2 3 4 |
CSBLOCK(&cs) { // Manipulate some shared data here. } |
블록이 의미하는 바가 무엇인지 분명히 나타나며, 사용자는 새로운 변수에 대해서 고민하지 않아도 되며, 이를 위해서 희생해야 하는 성능상의 손실은 if문 내에서 발생하는 한 번의 비교뿐이다.
부라보~
Pingback: Critical Section Block 2 | 개.발.인생