- 모든 자원이 힙에서 생기지는 않기 때문에, 우리는 필요에 따라, 자원 관리 클래스를 직접 만들어야 할 경우도 있습니다.
- RAII 기법에 따라, 뮤텍스 잠금을 관리하는 클래스를 만든다면, 아래 예제 처럼 작성 할 수 있습니다.
RAII 패턴은 C++ 같이 개발자가 직접 resource 관리를 해주어야 하는 언어에서 leak 을 방지하기 위한 중요한 기법으로 해당 리소스의 사용 scope이 끝날 경우에 자동으로 해제를 해주며 exception이 발생하거나 하는 경우에도 획득한 자원이 해제됨을 보장하여
robust code 코드를 작성할 수 있다.
robust code 코드를 작성할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| class Lock { public : explicit Lock(Mutex *pm) : mutexPtr(pm) { lock(mutexPtr); } ~Lock() { unlock(mutexPtr); } private : Mutex *mutexPtr; } void main() { Mutex m; { Lock m1(&m); } } |
- 생성시, 잠금을 걸고, 블럭을 나가면서 잠금을 해제할 것 입니다.
만약, 같은 객체로 Lock을 한번 더 하게 된다면, 어떻게 되어야 할까요?
1
2
| Lock m1(&m); Lock m2(m1); |
아래의 규칙을 참고하여, 해당 하는 내용을 작성해 봅니다.
1. 복사를 금지 합니다.
복사하면 안되는 RAII 클래스에 대해서는 반드시 복사가 되지 않도록 막아야 합니다.
1
2
| class Lock : private Uncopyable { |
2. 관리하고 있는 자원에 대해 참조 카운팅을 수행합니다.
해당 자원을 참조하는 객체의 개수에 대한 카운트를 증가시키는 식으로 RAII 객체의 복사동작을 만들어야 합니다.
tr1::shared_ptr를 사용 할 수 있는데, 기본 동작이 참조 카운트가 0이 되면 대상을 삭제해 버리기 때문에,
삭제자를 지정하여 사용 합니다. 삭제자는 참조 카운트가 0이 되었을 때 호출되는 함수 혹은 함수 객체를 말합니다.
1
2
3
4
5
6
7
8
9
10
11
| class Lock { public : explicit Lock(Mutex *pm) : mutexPtr(pm, unlock) { lock( mutexPtr.get() ); } private : std::tr1::shared_ptr<mutex> mutexPtr; } </mutex> |
- 위 코드를 보면, 소멸자 선언이 사라졌습니다.
클래스의 소멸자는 비정적 데이터 멤버의 소멸자를 자동으로 호출하게 되어 있습니다.
이 '비정적 데이터 멤버'에 해당하는 것이 mutexPtr입니다.
그런데, mutexPtr의 소멸자는 뮤텍스의 참조 카운트가 0이 될 때, 삭제자를 자동으로 호출합니다.
위 코드에서는 컴파일러가 생성한 소멸자를 통해, 뮤텍스의 참조 카운트가 0이 되면, unlock을 호출합니다.
3. 관리하고 있는 자원을 진짜로 복사합니다.
- 때에 따라서는 자원을 원하는 대로 복사 할 수도 있습니다.
자원 관리 객체를 복사하면 그 객체가 둘러싸고 있는 자원까지 복사되어야 합니다. [깊은 복사(deep copy)]
4. 관리하고 있는 자원의 소유권을 옮깁니다.
- 특정한 자원에 대해 그 자원을 실제로 참조하는 RAII 객체는 딱 하나만 존재하도록 만들고 싶을때,
auto_ptr과 같이 소유권을 이동하는 동작을 생각 할 수 있습니다.
* RAII 객체이 복사는 그 객체가 관리하는 자원의 복사 문제를 안고 가기 때문에,
그 자원을 어떻게 복사하느냐에 따라 RAII 객체의 복사 동작이 결정 됩니다.
* RAII 클래스에 구현하는 일반적인 복사 동작은 복사를 금지하거나 참조 카운팅을 해주는 선으로 마무리하는 것입니다.
하지만 이 외의 방법들도 가능하니 참고해 둡시다.
댓글 없음:
댓글 쓰기