2013-10-11 2 views
1

비동기를 메인 큐 또는 전용 디스패치 큐 (직렬)로 디스패치하고 디스패치 코드 블록에서 @synchronized하는 코드를 보았습니다. 어떤 상황에서 그렇게하고 싶습니까? 직렬 대기열에서 이미 동기화가 필요하지 않습니까?dispatch_async 내의 동기화 된 블록

동기화 된 블록을 다른 GCD 디스패치로 교체 할 수 있습니까?

답변

1

대기열 예, 동기화되었지만 내부의 '외부'개체에 액세스하면 동기화되지 않습니다.

스레드 수가 많은 경우 각 스레드가 개체를 켭니다. Tipical case는 CoreData 가져 오기를 비동기 적으로 수행 할 때 컨텍스트 또는 저장소 코디네이터를 동기화해야합니다.

+0

비동기 코어 데이터 저장을 비공개 대기열에서 수행 할 경우 @synchronize 할 필요가 없습니다. – Abizern

+0

개인 대기열에서 no.이 경우 필요한 경우에만 상점 만 동기화 할 수 있습니다. – Leonardo

3

@synchronized()은 (주어진 토큰에 대해 @synchronized의 인수로 사용 된) 포함 된 코드가 한 번에 하나의 스레드에서만 실행되도록합니다.

직렬 대기열에 제출 된 블록은 한 번에 하나씩 실행됩니다. 주어진 블록은 실행을 완료하기 전에 제출 된 모든 블록이 실행될 때까지 실행되지 않습니다. 직렬 리소스 큐에서 실행되는 코드에서만 공유 리소스에 액세스하는 한 액세스를 동기화/잠금 할 필요가 없습니다. 그러나 주어진 큐가 연속적이기 때문에 다른 큐/스레드 (심지어 직렬 큐!)가 동시에 실행되지 않고 동일한 공유 리소스에 액세스한다는 것을 의미하지는 않습니다.

@synchronized()을 사용하면 이러한 다중 스레드/큐가 동시에 리소스에 액세스하지 못하게하는 한 가지 방법입니다. 공유 리소스에 액세스하는 모든 코드는 @synchronized()으로 묶어야합니다.

예. 동기화 된 블록 대신 다른 GCD 디스패치를 ​​사용할 수 있습니다. 이 작업을 수행하는 "GCD 방법"은 직렬 대기열을 사용하여 공유 자원에 대한 모든 액세스를 직렬화하는 것입니다. 따라서 공유 리소스에 대한 액세스가 필요할 때마다 리소스와 연결된 직렬 대기열에 해당 코드 (사용 사례에 따라 dispatch_sync() 또는 dispatch_async() 사용)를 전달합니다. 물론 이는 공유 리소스에 액세스하는 프로그램의 모든 부분에서 리소스 액세스 대기열을 볼 수 있어야하며 액세스 할 수 있어야합니다. (당신은 기본적으로는 사용 할 필요가 곳의 잠금 토큰이 액세스 할 수 있어야한다는 점에서 @synchronized()과 같은 문제가 있지만, 단지 상수 문자열이 될 수 있기 때문에 좀 더 쉽다.)

1

스레드 안전 가변 만들기에 관한 것입니다 공유 상태는 변경 불가능하거나 공유되지 않습니다. 이 경우 synchronize 및 직렬 대기열은 일시적으로 공유를 해제 (동시 액세스를 방지)하는 방법이며 둘 다 유효합니다.

그러나 같은 개체 안에 관련 정보가 서로 떨어져있는 경우를 생각해보십시오. 예를 들어, 주소 (도시, 거리 등) 1), 가격, 세금, 할인 2)이있는 청구서. 일관성없는 상태 (오브젝트 A는 새로운 거리를 설정하고 오브젝트 B는 오래된 도시와 새로운 거리를 읽는)를 피하기 위해 둘 다 보호해야하지만 둘 다 관련이 없습니다. 이 경우 관련성이 낮은 코드 간 블록을 피하려면 낮은 수준의 세분성을 사용해야합니다.

규칙은 다음과 같을 수 있습니다. 동일한 객체 내부에서 불필요한 블록을 발생시킬 수 있으므로 관련없는 변수 세트에서 동기화를 사용하지 마십시오. 대기열 + 동기화 또는 집합 당 대기열을 사용할 수 있지만 두 세트에서 동기화되지는 않습니다.

키는 synchronize이 개체의 유일한 고유 잠금을 나타내며 해당 토큰을 한 번만 들릴 수 있다는 것입니다.하나의 큐를 통해 관련된 모든 코드를 라우팅하는 것과 동일한 목표를 달성합니다. 단, 여러 개의 큐 (따라서 세분성이 더 낮음)를 가질 수 있지만 하나의 고유 잠금 만 가질 수 있다는 점은 다릅니다.

예제로 돌아갑니다. 객체가 "상태 X가 synchronize에 의해 보호됨"으로 문서화되었다고 가정하면, synchronize을 대기열에 사용하면 같은 상태에 액세스 할 수있는 관련 메소드를 차단하는 데 유용합니다. 어쩌면 대기열과 동기화가 서로 다른 것을 보호하거나 직렬 대기열이 다른 작업을 수행 할 수 있습니다.

대기열을 선호하는 또 다른 이유는 읽기 - 쓰기 잠금과 같은보다 정교한 패턴을 작성하는 것입니다. 예 :

+0

장벽이 비동기입니까? 나는 그 존재를 결코 알지 못했다. 미리 감사드립니다. – Unheilig

+2

디스패치 장벽을 사용하면 사용자 지정 동시 디스패치 큐 내에 동기화 지점을 만들 수 있습니다 (글로벌 큐에서는 작동하지 않음). dispatch_barrier_ [a] sync_ [f]에는 4 가지 변형이 있습니다. f는 함수를 실행하는 것입니다. 그들은 다음과 같이 작동합니다. 1) 차단 블록을 대기열에 제출합니다. 2) 실행이 장벽 블록에 도달하면 장벽이 실행되기 전에 모든 블록이 제출 될 때까지 대기열이 중지됩니다. 3) 장벽 블록이 단독으로 실행됩니다 (이 시점에서 다른 블록이 실행되지 않음). 4) 대기열이 평소대로 계속됩니다. – Jano

+0

다시 +1 할 수 있기를 바랍니다. 하지만이 dispatch_barrier_ [a] sync_ [f] 장점을 사용할 수있는 예제를 인용 할 수 있습니까? – Unheilig