멀티스레드를 활용할 경우가 많아지면서 자연스럽게 동기화 문제가 따라오게 되었습니다. 이 문제를 해결하기 위한 기본적인 방법은 중요한 지점(Critical Section)에 접근을 통제하는 것입니다. 이를 위한 방법론으로 lock, semaphore 등이 있는데 오늘은 Foundation에서 기본적으로 제공하는 NSLock과 관련 클래스들을 살펴보도록 하겠습니다.
-
NSLocking
모든 Lock 클래스가 채택하고 있는 프로토콜입니다. lock()과 unlock() 메소드를 필수로 구현하도록 요구합니다. 이 프로토콜을 채택한 Lock 객체들의 사용법은 거의 유사한데 다음과 같습니다.lock.lock() // lock을 시도하고, 성공할 때 까지 스레드가 block됩니다. // Critical Section lock.unlock() // lock을 해제하서, 다른 스레드가 들어갈 수 있도록 합니다.
-
NSLock
가장 기본적인 Lock 객체입니다. 위에서 제시한 lock(), unlock()을 제공함과 동시에 ‘lock을 얻을 때 까지 스레드를 block한다’는 점을 완화하기 위해 다음과 같은 메소드들을 제공합니다.-
lock(before:): 특정 시점까지 lock을 획득하도록 시도합니다. lock을 얻는 즉시 true를 반환하고, 특정 시점까지 lock을 획득하지 못한다면 false를 반환합니다. 이 메소드를 사용하면 특정 시점 이후에는 스레드가 block 되지 않음을 보장할 수 있습니다.
-
try(): lock을 획득할 수 있는 지를 시도합니다. 성공하면 true, 실패하면 false를 반환합니다. 단발성으로 실행하기 때문에 스레드가 block되지 않습니다.
그 외에도 Lock에 이름을 부여해 줄 수 있는 name 프로퍼티 등이 부가적으로 제공됩니다.
NSLock은 lock을 거는 스레드와 unlock하는 스레드가 동일할 것을 요구합니다. 다른 스레드에서 unlock을 시도할 경우는 정의되지 않은 행동(=오류)이 발생합니다. 또한 같은 스레드에서 2번 이상 lock을 호출하면 스레드가 영원히 block됩니다.
-
-
NSRecursiveLock
NSLock과 비슷하나 동일 스레드에서 lock을 시도할 경우는 통과시키는 특성을 가지고 있습니다. 즉 동일 스레드에서는 여러번 lock을 걸 수 있고, 다른 스레드에서는 lock을 걸 수 없습니다. 내부적으로 lock을 건 횟수를 카운팅해서 카운트가 0이 되면 다른 스레드에서도 lock을 시도할 수 있습니다. -
NSConditionLock
Lock을 획득하기 위한 조건을 설정할 수 있습니다. 이 조건은 단일 Int형의 값으로 나타나는데, 초깃값 혹은 unlock을 할 때 값을 바꿔줄 수 있습니다. 기존처럼 무조건 적으로 lock을 얻을 수도 있지만, 자신이 원하는 조건 값이 될 때에만 lock을 걸 수 있도록 제한을 할 수도 있습니다. -
NSCondition
POSIX의 Condition Variable을 구현한 것입니다.참조 아래와 같은 과정을 통해 사용합니다.-
condition 변수에 lock() 메소드를 통해 lock을 겁니다.
- 조건이 될 때 까지 wait()을 호출하며 대기합니다.
while (!(boolean_predicate)) { condition.wait() }
-
조건을 통과하게 되면 실제 작업을 수행해줍니다.
-
이후에 signal() 혹은 broadcast()를 호출하여 기다리고 있는 스레드들이 다시 조건을 체크할 수 있도록 합니다.
- condition의 lock을 해제합니다.
-