iOS/Swift

Swift ;; GCD #3 Sync 사용 시 주의할 점

may_wonhui 2023. 3. 15. 17:06

앞서

특정 스레드에서 async로 작업을 보내면 해당 스레드는 기다리지 않고 다음 작업을 진행할 수 있는 것이고,

sync로 작업을 보내면 해당 스레드는 그 작업이 완료될 때까지 기다려(블락되어) 다음 작업을 진행할 수 없는 것이라고 했다.

 

https://may1coding.tistory.com/56

 

Swift ;; GCD #2 Async와 Sync

앞서 GCD는 DispatchQueue를 사용하여 작업을 분산한다고 했다. https://may1coding.tistory.com/55 Swift ;; GCD(Grand Central Dispatch) #1 정의 GCD는 동시성 프로그래밍을 위해 Apple이 제공하는 API이다. (iOS 8부터 지원)

may1coding.tistory.com

 

이번에는 sync를 사용할 때 어떤 주의 사항이 있는지 알아보려고 한다!

 

1. 메인 스레드에서 작업을 분산 처리할 때(task를 DispatchQueue로 보낼 때)는 항상 async로 보내야 한다.  

그 목적지가 메인이건, 글로벌이던 간에!!

 

 

목적지가 메인이라면 (메인->메인) >

(현재 메인 스레드라면)

메인 스레드에서 메인 스레드로 sync task를 보내면

서로가 서로의 작업이 끝나기만을 기다리는 데드락 현상이 발생할 수 있다.

//데드락 발생 가능
DispatchQueue.main.sync {

}

 

그림으로 보기!

1. 메인에서 메인 큐로 작업을 sync로 보냈다.

sync 작업이기 때문에 메인은 블락되고 해당 작업이 완료될 때까지 기다린다.

 

2. 메인 큐는 받은 작업을 메인 스레드로 할당하려고 한다. (메인 큐는 메인 스레드로 작업을 할당하는 큐)

그런데, 메인 스레드는 해당 작업이 완료될 때까지 블락된 상태이다.

이 때, 블락된 메인 스레드에 접근하려고 하므로 데드락(교착 상태)이 발생한다.

따라서 앱이 터지는, 크래시가 발생한다.

 

 


목적지가 글로벌이라면 (메인->글로벌) >

DispatchQueue.global().sync {

}

 

그림으로 보기!!

1. 메인에서 global 큐로 sync task를 보낸다.

 

2. 해당 task가 완료될 때까지 메인 스레드는 블락되어 다음 작업을 처리하지 못하고 기다린다.

 

이렇게 되면, 자주 경험해봤던 스크롤이 버벅인다던가 화면이 버벅거리는 현상이 발생한다.

 


2. 같은 큐에서 같은 큐로 sync task를 보내면 안 된다.

 

마찬가지로, 같은 큐로 sync task를 보내도 데드락 현상이 발생할 수 있다.

 

이렇게 하면 안된다!

//데드락 발생 가능
DispatchQueue.global().async {
	DispatchQueue.global().sync {
    	//task
    }
}

 

1번 주의 사항인 메인 -> 메인으로 작업을 sync로 보내지 말라는 것과 동일하다.

 

위의 코드만 봤을 때는 이해가 가지 않을 수도 있다.

그림으로 보면 이렇다.

 

1. 큐는 Thread2에 async 특성을 가진 Task1을 할당한다.

 

2. Task1의 작업 내용은 작업을 global 큐로 sync로 보내는 것이다.

따라서 Thread2에서 같은 큐로 sync로 작업을 보냈다.

sync로 보냈으므로 해당 작업이 완료될 때까지 Thread 2는 블락된 상태로 기다리고 있다.

 

근데, 큐의 역할은 무엇이었나? 큐 내부의 작업들을 여러 스레드로 분산처리 해주는 것이다.

 

예를 들어 해당 큐는 Thread 2, Thread 3, Thread 4에 작업을 보낼 수 있는 큐라고 한다면

다시 Thread2로 작업을 보내려고 할 수도 있다.

(Thread 3, 4로 보낼 수도 있지만 Thread 2로 보낼 수도 있다. 우리가 결정하는 게 아니라, 시스템이 결정하는 것임.

Thread 2로 보내는 경우 데드락이 발생한다.)

 

Thread 2는 보낸 작업이 완료되기만을 기다리고 있는 블락 상태인데,

큐는 또 다시 Thread 2에 작업을 보내려고 하고 있으므로 교착 상태가 발생하는 것이다.

 

 

 


그러면 sync는 왜 있는 걸까??? 의문이 생긴다.

이는 순서가 중요한 작업을 처리할 때 사용한다.

 

예를 들어 task1, task2, task3이 있다.

task2는 task1에서 연산된 값 a를 조작하는 task를 해야 한다.

이럴 경우, task1을 async로 보내버리면 task1의 연산이 끝나기도 전에

task2가 a에 접근하여 결과적으로 예상한 값이 나오지 않는 race condition 이 발생할 수도 있다.

 

이를 방지하기 위한 대안으로, sync를 사용할 수 있는 것!

 


참고

https://www.inflearn.com/course/iOS-Concurrency-GCD-Operation/dashboard

 

iOS Concurrency(동시성) 프로그래밍, 동기 비동기 처리 그리고 GCD/Operation - 디스패치큐와 오퍼레이션

동시성(Concurrency)프로그래밍 - iOS프로그래밍에서 필요한 동기, 비동기의 개념 및 그를 확장한 GCD 및 Operation에 관한 모든 내용을 다룹니다., - 강의 소개 | 인프런

www.inflearn.com