2011-09-08 2 views
4

GCD 동기 큐 (dispatch_sync)를 사용하여 코드의 중요 섹션을 구현해야한다고 읽었습니다. 예를 들어 계정 잔액에서 거래 금액을 뺀 블록이 있습니다. 동기화 호출의 흥미로운 부분은 질문입니다. 여러 스레드에서 다른 블록의 작업에 어떤 영향을 미칩니 까?동기화 GCD 대기열에 블록을 올려 놓으면 블록이 잠기고 다른 블록이 일시 중지됩니까?

비동기 모드에서 메인 및 사용자 정의 큐의 시스템 정의 블록과 사용자 정의 블록을 모두 사용하고 실행하는 3 개의 스레드가있는 상황을 생각해보십시오. 이 블록들은 모두 어떤 순서로 병렬로 실행됩니다. 이제 블록이 동기화 모드로 사용자 정의 대기열에 저장되면 다른 모든 블록 (다른 스레드 포함)은 블록 실행이 완료 될 때까지 일시 중지됩니까? 그렇지 않으면 다른 블록이 실행되는 동안 일부 블록 만 해당 블록에 놓이게됩니다. 그러나 다른 블록이 동기화 블록과 동일한 데이터를 사용하는 경우 다른 블록이 해당 잠금이 해제 될 때까지 대기해야합니다.

IMHO 상관 없지만 하나 또는 여러 개의 코어가 있으며 동기화 모드는 전체 앱 작업을 중단해야합니다. 그러나 이것들은 제 생각 일 뿐이므로 귀하의 통찰력을 공유하십시오.

+0

"동기 대기열"이 없습니다. 동기 디스패치 (블록 완료를 기다리는)와 비동기 디스패치 (블록을 ​​큐에 추가하는 것)가 있습니다. 동시 및 순차적 대기열이 있습니다. 순차적 큐는 중요한 섹션을 구현하는 데 사용할 수 없지만 중요한 섹션의 필요를 피하기 위해 매우 유용합니다. – gnasher729

답변

7

동기식 디스패치는 전달 된 블록이 완료 될 때까지 코드 실행을 일시 중단합니다.

dispatch_sync(somewhere, ^{ something }); 
// Reached later, when the block is finished. 

dispatch_async(somewhere, ^{ something }); 
// Reached immediately. The block might be waiting 
// to be executed, executing or already finished. 

을 그리고 직렬 및 동시 파견 큐의 두 가지 종류가 있습니다 : 비동기 파견 반환 즉시 블록이 호출 코드와 관련하여 비동기 적으로 실행됩니다. 일련의 블록은 추가되는 순서대로 블록을 하나씩 엄격하게 전달합니다. 사람이 끝나면 다른 사람이 시작됩니다. 이러한 종류의 실행에는 하나의 스레드 만 필요합니다. 동시 큐는 블록을 동시에 병렬로 디스패치합니다. 거기에 더 많은 스레드가 사용되고 있습니다.

sync/async 디스패치와 직렬/동시 대기열을 원하는대로 혼합하여 일치시킬 수 있습니다. GCD를 사용하여 중요한 섹션에 대한 액세스를 보호하려는 경우 단일 직렬 대기열을 사용하고이 대기열의 공유 데이터에 대한 모든 작업을 동 기적 또는 비동기 적으로 (중요하지 않음) 전달하십시오. 그 방법은 항상 공유 데이터와 함께 운영 한 블록이있을 것이다 : 이제

- (void) addFoo: (id) foo { 
    dispatch_sync(guardingQueue, ^{ [sharedFooArray addObject:foo]; }); 
} 

- (void) removeFoo: (id) foo { 
    dispatch_sync(guardingQueue, ^{ [sharedFooArray removeObject:foo]; }); 
} 

guardingQueue 직렬 큐 인 경우, 추가/작업이 addFoo:removeFoo: 방법이 다른에서 동시에 호출되는 경우에도 충돌 할 수 없다 제거 스레드.

+0

그런 다음 두 블록 (하나의 asyn A와 다른 sync B)이 다른 스레드에서 실행되지만 둘 다 같은 개체 (예 : 잔액 계정)를 사용하는 상황은 어떻습니까? 중간 블록에서 동기화 B 블록이 시작되고 블록 A가 계정을 읽으 려 할 때 균형을 업데이트하면 경쟁이 발생합니까? 블록 A가 데이터를 읽지 못하게하기 위해 명시 적으로 조치를 취 했습니까? – Centurion

+0

질문에서 알 수 있듯이 직렬 대기열을 사용하고 동기화 모드로 블록을 발송하면 블록이 완료 될 때까지 발신자 코드가 고정됩니다. 공유 리소스를 읽기/쓰기로부터 보호하기위한 다른 보호는 없습니다. – Centurion

+0

동기화/비동기 블록이나 대기열에 대해 이야기하는 것은 의미가 없습니다. 동기식 또는 비동기식은 블록을 큐에 전달하는 것입니다. 중요한 부분을 GCD로 보호하는 방법을 설명하는 답변을 업데이트했습니다. 도움이 되길 바랍니다. – zoul

2

아니요.

동기화 된 부분은 블록이 큐에 저장되지만 블록이 반환 될 때까지 컨트롤이 호출중인 함수로 전달되지 않는다는 것입니다.

GCD의 많은 용도는 비동기식입니다. 블록을 대기열에 넣고 블록 완료를 기다리는 대신 작업 제어를 호출 함수에 전달합니다.

다른 대기열에는 영향을주지 않습니다.

1

특정 리소스에 대한 액세스를 직렬화해야하는 경우 액세스 할 수있는 메커니즘이 두 개 이상 있습니다.객체를 가지고 있지 않지만이 인에 대한 C 구조를 사용하는 경우

@synchronize(accountObject) { ... } 

: 당신이 계정 개체가있는 경우, 다음과 같은 작업을 수행 할 수 있습니다 (즉, 주어진 계좌 번호 고유) 주어진 계좌 번호에 대해 하나 명의 같은 구조는 다음 다음을 수행 할 수 있습니다 :이

// Should be added to the account structure. 
// 1 => at most 1 object can access accountLock at a time. 
dispatch_semaphore_t accountLock = dispatch_semaphore_create(1); 

// In your block you do the following: 
block = ^(void) { 
    dispatch_semaphore_wait(accountLock,DISPATCH_TIME_FOREVER); 
    // Do something 
    dispatch_semaphore_signal(accountLock); 
}; 

// -- Edited: semaphore was leaking. 
// At the appropriate time release the lock 
// If the semaphore was created in the init then 
// the semaphore should be released in the release method. 
dispatch_release(accountLock); 

, 관계없이 큐의 동시성의 수준을, 당신은 하나 개의 스레드가 어떤에서 계정에 액세스하는 것을 보장 주어진 시간.

더 많은 유형의 동기화 개체가 있지만이 두 가지는 사용하기 쉽고 매우 유연합니다.

+0

정확히 내가 필요한 것! 경미한 유형. 'dispatch_semaphore_wait'는 2 개의 인수를 취합니다. 'dispatch_semaphore_wait (accountLock, DISPATCH_TIME_FOREVER);와 같은 것이 트릭을 수행해야합니다. –

+0

세마포어 작업이 끝나면 설명서에 'dispatch_release'라고되어 있습니다. 나는 내가 할 때마다 추락한다. 내가 뭘하고 있는지 잘 모르겠다. 어느 쪽이든,이 스 니펫의 세마포어가 유출됩니다. –

+0

세마포어가 누출되는 것이 맞습니다. 잘못된 순간에 세마포를 해제하려고하기 때문에 충돌 할 수 있습니까? 잠금이 오브젝트와 함 2 작성되면 오브젝트가 해제 될 때 해제되어야한다고 가정하십시오. 그 효과를 위의 코드에 주석을 추가하겠습니다. – aLevelOfIndirection

관련 문제