본문 바로가기

이상/iOS

[iOS] DispatchQueue - DispatchQueue.main.sync에 대해

반응형

이전 GCD 관련 글에서 Main Queue는 sync로 실행할 경우 데드락에 빠지게 되니

 

async로만 실행해야 한다고 Apple Doc에 나와있다고 했다.

 

근데 왜 그렇게하면 데드락에 빠지는건데? 라는 생각이 들었다.

 

대부분의 블로그에서 그 이유는 Main Thread가 Thread-safe 하지 않기 때문이라고 한다.

 

일단 이 글을 한 번 쭉 읽어보자. 귀찮으면 다 읽어 볼 필요도 없다.

 

첫번째 이미지와 첫번째 소제목만 읽으면 된다.

 

앱이 시작되는 순서와 그 순간들에 작동하는 코드

 

위 이미지는 사용자가 아이폰에서 앱 아이콘을 탭한 후 앱이 실행되기까지의 과정을 보여준다.

 

첫번째 소제목에는 이렇게 적혀있다.

 

Run Loop is a mechanism that allows threads to process events at any time without exiting.

 

Run Loop는 Threads가 at any time without exiting하게 이벤트를 처리할 수 있게 해주는 메커니즘이다.

 

Launch Time이 다 끝나고 Running 부분에서 Event Loop가 계속 돌고 있는데 저 부분이다.

 

Run Loop와 Thread 앞에 Main을 붙여보면

 

Main Run Loop는 Main Thread가 언제든지 종료되지 않게

 

즉, 항상 살아있어서 이벤트를 언제든 처리할 수 있게 해준다는 의미가 된다.

 

그보다 아래에 보면 더 자세한 내용이 있다.

 

We have NSRunLoop and CFRunLoopRef for same purpose.
CFRunLoopRef is inside the CoreFoundation framework. It provides APIs for pure C functions, all of which are thread-safe.
NSRunLoop is a wrapper based on CFRunLoopRef that provides object-oriented APIs, but these APIs are not thread-safe.

.
The key point is the UIApplicationMain() function. This method will set an NSRunLoop object for the main thread.

 

Run Loop에는 같은 목적으로 NSRunLoop와 CFRunLoopRef가 있는데

 

둘의 차이점은 thread-safe하냐 하지 않냐라고 한다.

(thread-safe: 개체를 동시에 둘 이상의 스레드로 수정할 수 없다)

 

그리고 UIApplicationMain()에서 Main Thread NSRunLoop object set한다고 한다.

 

Main Thread의 Run Loop는 thread-safe하지 않는 NSRunLoop이기 때문에

 

둘 이상의 스레드에서 같은 객체를 수정할 수 있게 된다.

 

하지만 같은 객체를 둘 이상의 스레드에서 수정을 하게 되면

 

예를 들어 하나의 변수에 각기 다른 값을 넣으려는 시도와 같은 문제가 생길 수 있을 것 같은데

 

왜 그렇게 만들었을까?

 

Zedd님의 블로그에 정리된 걸 보니

 

각 프레임워크에는 Thread로부터 안전한 영역과 안전하지 않는 영역이 있다고 한다.

 

그럼 Thread-safe하지 않기 때문에 deadlock이 발생하는건 아닌 것 같다.

 

 

여기부턴 주관적인 생각이다.

 

이전 글에서 보면 Main Queue는 다른 Queue와는 다른 특수한 Queue이기 때문에

 

현재 runloop의 실행이 끝난 후에 순서대로 Main Queue에 담긴 task들이 실행된다.

(다시 한 번 참고.

항상 그런 것은 아니지만 대부분의 UI이벤트가 Main Thread에서 실행되기 때문에

그렇다고 표현될 수도 있을 것 같다.

참고 링크 답변의 가장 위에서 말하는 것처럼

Background Queue에서 코드가 실행 중일 때

Main Thread에서 실행할 task가 있을 경우에 주로 사용한다는 점을 숙지해야겠다.)

 

Main Queue를 async로 사용할 때는

 

async이므로 Main Queue에 task를 추가하고 즉시 반환하기 때문에 문제가 없지만

 

sync로 사용할 때는 Main Queue에 task를 추가하고 해당 task가 종료될 때까지 기다린 후 반환되는데

 

Main Queue는 현재 runloop가 다 실행된 후(after the current runloop completes)에 task들이 실행되므로

 

task가 실행될 수 없기 때문에 여기서 모순이 생기고 deadlock 상태가 된다.

반응형