diff --git a/LEVEL 1/26.2-GCD.md b/LEVEL 1/26.2-GCD.md new file mode 100644 index 0000000..1d8808e --- /dev/null +++ b/LEVEL 1/26.2-GCD.md @@ -0,0 +1,49 @@ +# 26.2 - GCD +## 글로벌 큐(Global Queue)와 메인 큐(Main Queue)는 어떻게 다르나요? +- 두 개의 큐 모두 이미 만들어져있는 큐. + +- DispatchQueue.main + - Serial Queue + - main 큐에 작업을 추가하면, main 스레드에서 처리한다. + - 앱이 실행되는 동안에는 늘 메모리에 올라와 있다. + - 때문에 앱의 생명주기와 같은 생명주기를 가지며 main이 멈추면, 앱이 멈춘다. + - 전역적으로 사용이 가능하다. + - Main Runloop가 자동으로 설정되고 실행된다. + - UI 작업은 main에서만 가능하다. + +- DispatchQueue.global() + - Concurrent Queue + - global()이 호출되면 스레드가 작업을 처리하기 위해 메모리에 올라왔다가, 작업이 끝나면 제거된다. + + +### main은 property, global()은 method인 이유? +- main은 언제나 메모리에 올라와 있는 Default지만, global()은 매번 새로운 스레드를 만들어서 사용하지 때문에 다르지 않을까 싶다. + +### main.sync? +- main에서 main.sync를 호출하면, deadlock에 빠지게 된다. +- sync는 작업이 끝나기를 기다리기에 main에서 main.sync를 호출하면 main 스레드는 sync의 작업이 끝나기를 기다린다. +- 그런데 이때 작업을 해야하는 sync의 코드 블록도 main에서 실행되고 있던 코드이기에 똑같이 멈춰버린다. +- main은 sync가 끝나길, sync는 main이 동작하기를 기다리며 영원히 멈춰있게 된다. + +### UI 작업을 main에서 해야하는 이유? +- UIKit은 Thread Unsafe하기 때문에 여러 스레드에서 접근이 가능하다. +- 이는 Race Condition을 발생시킬 수 있고 이렇게 되면 의도대로 화면이 그려지지 않을 수 있고 때문에 Serial Queue가 필요하다. +- 다른 Serial Queue에 넣을 수도 있겠지만, UI를 그리기 위해서는 일정한 주기(View Drawing Cycle)에 맞추어 동작하는 RunLoop가 필요하다. +- 해당 주기에 맞추어 입력을 받아 UI를 그리기 때문이다. +- 모든 스레드가 각자의 RunLoop를 따라 UI를 그리게 된다면 UI가 그려지는 시점이 모두 달라진다. +- 이는 또다시 Race Condition이 일어날 수 있는 조건이 되기에, 기준을 Main RunLoop로 맞춰서 해결하는 것이다. +- 또한 자동으로 실행되는 RunLoop가 Main RunLoop밖에 없기 때문이기도 하다. + +### RunLoop? +- 작업을 예약하고 들어오는 이벤트 수신을 조정하는 데 사용하는 이벤트 처리 루프이다. +- 작업이 있을 때는 스레드를 바쁘게 유지하고, 작업이 없을 때는 스레드를 휴면 상태로 만드는 것을 목적으로 둔다. + +![image](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Multithreading/Art/runloop.jpg) + +- 이는 RunLoop의 동작 방식에서 알 수 있는데, 그림의 Input Source처럼 이벤트가 들어오더라도 RunLoop를 실행시키지 않는다면, RunLoop는 대기 상태에서 기다리며 이벤트를 처리하지 않는다. + +![스크린샷 2025-01-23 오후 3 00 29](https://github.com/user-attachments/assets/17ab603c-1b49-473a-82f5-e502f501ec5a) + +- 위와 같은 4개의 함수를 사용해 RunLoop를 작동시키면, 그제서야 이벤트를 받고, 이에 대한 작업 처리를 한다. +- 때문에 main이 아닌 스레드에서 RunLoop가 필요한 작업을 하기 위해서는 개발자가 별도로 RunLoop를 반복 실행하는 로직이 필요하다. +- main의 Main RunLoop는 앱이 실행될 때 프레임워크 차원에서 자동으로 RunLoop를 설정하고 실행한다.