사실 이미 iOS 6.0 에서 deprecated 이다.
- 데드락을 막기 위해서
- (NSString*)someString {
__block NSString *localSomeString;
dispatch_sync(_syncQueue, ^{
localSomeString = _someString;
});
return localSomeString;
}
- (void)setSomeString:(NSString*)someString {
dispatch_async(_syncQueue, ^{
_someString = someString;
});
}
이 경우 syncQueue 에서 someString 의 getter 를 부르면 데드락이 발생한다.
그래서 다음과 같은 코드를 작성하게 된다.
- (NSString*)someString {
__block NSString *localSomeString;
dispatch_block_t accessorBlock = ^{
localSomeString = _someString;
};
// 지금 queue 가 syncQueue 이면 sync 쓰지 말고 그냥 block 실행
if (dispatch_get_current_queue() == _syncQueue) {
accessorBlock();
} else {
dispatch_sync(_syncQueue, accessorBlock);
}
return localSomeString;
}
하지만 이 코드는 여전히 위험하고 데드락에 빠질 수 있다.
- 이건 반드시 데드락에 걸리는 코드다.
dispatch_sync(queueA, ^{
dispatch_sync(queueB, ^{
dispatch_sync(queueA, ^{
// Deadlock
});
});
});
- 그럼 이걸 아까의 방법으로 피해갈 수 있을까?
dispatch_sync(queueA, ^{
dispatch_sync(queueB, ^{
dispatch_block_t block = ^{ /* … */ };
if (dispatch_get_current_queue() == queueA) {
block();
} else {
dispatch_sync(queueA, block);
}
});
});
-
할 수 없다. 왜냐하면 dispatch_get_current_queue() 는 queueB 를 반환하기 때문.
-
큐가 계층 구조로 되어 있기 때문에 (queueB -> queueA) 이런 검사는 항상 잘못된 결과를 주게 될 것이다.
-
이 상황에서의 정답은, 동기화에 사용된 큐에서 절대로 someString getter 를 호출하지 않아야 한다는 것이다.
-
queue 는 매우 가벼운 객체이기 때문에 property 별로 각각 queue 를 만들어 사용해도 괜찮다.
- GCD 에 있는 queue-specific data 함수를 사용한다.
이 함수를 사용하면 임의의 데이터를 큐에 key-value 로 연관시킬 수 있다.
그리고 특정 키에 연관된 데이터가 없으면 계층 구조를 따라 올라가거나 최상위 계층에 다다를 때까지 찾는다.
??
dispatch_set_target_queue(queueB, queueA);
dispatch_queue_set_specific(queueA,
&kQueueSpecific, // key (void *)
(void*)queueSpecificValue, // value
(dispatch_function_t)CFRelease);
dispatch_sync(queueB, ^{
dispatch_block_t block = ^{ NSLog(@"No deadlock!"); };
CFStringRef retrievedValue = dispatch_get_specific(&kQueueSpecific);
if (retrievedValue) {
block();
} else {
dispatch_sync(queueA, block);
}
});
- 이때 key 는 포인터 값으로 비교한다. 그래서 ARC 환경인데 key 에 객체를 사용하면 메모리 관리가 힘들다.
- 하지만 위의 예처럼 CoreFoundation 객체를 사용하면 ARC가 메모리 관리를 신경쓰지 않기 때문에 편리하다.
- 디버깅할 때 (release 에 포함되지 않는다면)