2011-04-08 3 views
3

GCD (Grand Central Dispatch)를 사용하여 리소스에 대한 액세스를 제어하는 ​​동시 읽기 단독 쓰기 모델을 구현하는 올바른 방법을 이해하려고합니다.GCD를 사용하여 동시 읽기 단독 쓰기 모델 구현

NSMutableDictionary가 많이 읽혀지고 잠시 후에 업데이트된다고 가정합니다. 독서가 항상 사전의 일관된 상태로 작동하도록하는 올바른 방법은 무엇입니까? 물론 큐를 사용하고 사전에 대한 모든 읽기 및 쓰기 액세스를 직렬화 할 수는 있지만 사전에 동시에 액세스 할 수 있어야하는 읽기를 불필요하게 직렬화합니다. 처음에 그룹의 사용은 유망한 것으로 들립니다. 나는 '읽기'그룹을 만들고 모든 읽기 작업을 추가 할 수있었습니다. 그러면 동시에 읽기가 가능합니다. 그리고 나서 업데이트를 할 시간이되면 write 작업의 일부로 dispatch_notify() 또는 dispatch_wait()를 사용하여 업데이트가 완료되기 전에 모든 읽기가 완료되었는지 확인할 수 있습니다. 그렇다면 쓰기 작업이 완료 될 때까지 후속 읽기 작업이 시작되지 않도록하려면 어떻게해야합니까?
R1 : 여기서

제가 위에서 언급 한 사전을 갖는 예에있는 2 초 다른 판독 된이
완료 5 초를 필요 온다 : 0 초, 판독이되는이
R2를 완료하기 위해 5 초 필요 온다 W1 : 4 초에 쓰기 작업이 사전에 대한 액세스를 3 초 동안 필요로 함
R3 : 6 초에 다른 읽기가 완료되기까지 5 초가 필요함
W2 : 8 초에 다른 쓰기 작업도 3 초 필요함 완료하려면

이상적으로 abo 이처럼 재생해야 적이는 :
R1이 끝나는 10 초에서 시작하여 10
R3에서 종료 7 초 시작 7
W1에서 종료 2 초에서 시작하여 5
R2에서 종료 0 초 시작 15
W2는 15 초에서 시작하여 18에서 끝납니다.

참고 : R3이 6 초가 되더라도 W1이 먼저 오기 때문에 W1보다 먼저 시작하지 못했습니다.

위의 GCD를 구현하는 가장 좋은 방법은 무엇입니까?

답변

3

당신은 올바른 생각을 가지고 있다고 생각합니다. 개념적으로 바라는 것은 "barrier"블록을 제출할 수있는 개인 동시 대기열입니다. 따라서 barrier 블록은 이전에 제출 된 모든 블록이 실행을 완료 할 때까지 대기 한 다음 모두 실행합니다.

GCD는이 기능을 기본적으로 제공하지 않지만 일부 추가 논리에서 읽기/쓰기 요청을 래핑하고 이러한 요청을 중개 직렬 대기열을 통해 퍼널링하여 시뮬레이션 할 수 있습니다.

읽기 요청이 직렬 대기열의 맨 앞에 도달하면 dispatch_group_async은 실제 작업을 전역 동시 대기열에 전달합니다. 쓰기 요구의 경우에는 dispatch_suspend 직렬 대기열을 호출하고 dispatch_group_notify을 호출하여 이전 요청이 실행을 완료 한 후에 만 ​​동시 대기열에 작업을 제출하십시오. 이 쓰기 요청이 실행 된 후 큐를 다시 시작하십시오. 다음과 같은

뭔가 당신이 (필자는이 테스트를하지 않은 경우) 시작 수 :

dispatch_block_t CreateBlock(dispatch_block_t block, dispatch_group_t group, dispatch_queue_t concurrentQueue) { 
    return Block_copy(^{ 
     dispatch_group_async(concurrentQueue, group, block); 
    }); 
} 

dispatch_block_t CreateBarrierBlock(dispatch_block_t barrierBlock, dispatch_group_t group, dispatch_queue_t concurrentQueue) { 
    return Block_copy(^{ 
     dispatch_queue_t serialQueue = dispatch_get_current_queue(); 
     dispatch_suspend(serialQueue); 
     dispatch_group_notify(group, concurrentQueue, ^{ 
      barrierBlock(); 
      dispatch_resume(serialQueue); 
     }); 
    }); 
} 

사용 dispatch_async 직렬 큐에 이러한 포장 블록을 밀어.

+0

닉, 답장을 보내 주셔서 감사합니다. 아직 귀하의 솔루션을 테스트하지 못했지만, 그것이 효과가있는 것 같습니다! (필요한 유일한 수정 사항은 블록이 동기식으로 실행되지 않기 때문에 CreateBlock과 CreateBarrierBlock에 전달 된 블록을 Block_copy해야 함) – Yurie

+2

Apple은 이제 iOS 4.3/OS X 10.7부터 차단 블록 API를 제공합니다. DISPATCH_QUEUE_CONCURRENT 특성을 가진 큐를 생성해야하며, 차단 블록을 큐에 추가하려면 dispatch_barrier_async() 또는 dispatch_barrier_sync()를 사용하십시오. 문서는 에 있습니다. –

+0

@Christopher Nice find! 나는 애플이 이미 대중에게 공개했다는 것을 깨닫지 못했다. –

관련 문제