동시성 프로그래밍은 강력한 기능이지만 Race Condition Issue가 발생할 수 있다.
import Foundation
var cards = [1, 2, 3, 4, 5, 6, 7, 8, 9]
DispatchQueue.global().async {
for _ in 1...3 {
let card = cards.removeFirst()
print("야곰: \(card) 카드를 뽑았습니다!")
}
}
DispatchQueue.global().async {
for _ in 1...3 {
let card = cards.removeFirst()
print("노루: \(card) 카드를 뽑았습니다!")
}
}
DispatchQueue.global().async {
for _ in 1...3 {
let card = cards.removeFirst()
print("오동나무: \(card) 카드를 뽑았습니다!")
}
}
/* 출력예시
야곰: 1 카드를 뽑았습니다!
노루: 1 카드를 뽑았습니다! // 1 카드는 1장이지만 여러번 뽑히고 있다?!
오동나무: 1 카드를 뽑았습니다!
야곰: 2 카드를 뽑았습니다!
노루: 5 카드를 뽑았습니다!
야곰: 6 카드를 뽑았습니다!
노루: 8 카드를 뽑았습니다!
오동나무: 7 카드를 뽑았습니다!
오동나무: 9 카드를 뽑았습니다!
*/
let semaphore = DispatchSemaphore(value: 1) // count = 1
DispatchQueue.global().async {
semaphore.wait() // count -= 1 반드시 wait과 signal은 짝지어서 실행시켜야 한다.
semaphore.signal() // count += 1
}
이를 통해 위 예제의 문제를 해결하는 코드
import Foundation
var cards = [1, 2, 3, 4, 5, 6, 7, 8, 9]
let semaphore = DispatchSemaphore(value: 1)
DispatchQueue.global().async {
for _ in 1...3 {
semaphore.wait()
let card = cards.removeFirst()
print("야곰: \(card) 카드를 뽑았습니다!")
semaphore.signal()
}
}
DispatchQueue.global().async {
for _ in 1...3 {
semaphore.wait()
let card = cards.removeFirst()
print("노루: \(card) 카드를 뽑았습니다!")
semaphore.signal()
}
}
DispatchQueue.global().async {
for _ in 1...3 {
semaphore.wait()
let card = cards.removeFirst()
print("오동나무: \(card) 카드를 뽑았습니다!")
semaphore.signal()
}
}
import Foundation
var cards = [1, 2, 3, 4, 5, 6, 7, 8, 9]
let pickCardsSerialQueue = DispatchQueue(label: "PickCardsQueue")
DispatchQueue.global().async {
for _ in 1...3 {
pickCardsSerialQueue.sync {
let card = cards.removeFirst()
print("야곰: \(card) 카드를 뽑았습니다!")
}
}
}
DispatchQueue.global().async {
for _ in 1...3 {
pickCardsSerialQueue.sync {
let card = cards.removeFirst()
print("노루: \(card) 카드를 뽑았습니다!")
}
}
}
DispatchQueue.global().async {
for _ in 1...3 {
pickCardsSerialQueue.sync {
let card = cards.removeFirst()
print("오동나무: \(card) 카드를 뽑았습니다!")
}
}
}
결론은 Race Condition issue로 인한 것이다.
View Drawing Cycle
이라고 한다. 사실 모든 스레드는 각자의 Runloop를 가지게 되는데 만약 RunLoop에 따라 각자가 UI를 그리게 된다면 UI가 그려지는 시점이 모두 제각각이 되기 때문이다. 이렇게 되면 Race condition이 발생할 수 있다.출처: 야곰닷넷 동시성 프로그래밍 강좌