Swift: GCD - Race Condition / Thread Safe / DispatchSemaphore / Serial Queue

Wooyo·2023년 10월 27일
0
post-thumbnail

1. Race Condition

  • 여러개의 스레드를 사용하는 환경에서 코드가 동시에 실행되어 하나의 값에 동시에 접근하는 경우가 발생
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 카드를 뽑았습니다!
지민: 2 카드를 뽑았습니다!
민정: 5 카드를 뽑았습니다!
지민: 6 카드를 뽑았습니다!
민정: 8 카드를 뽑았습니다!
카리나: 7 카드를 뽑았습니다!
카리나: 9 카드를 뽑았습니다!
*/
  • card 배열은 1이 하나만 존재하는데 여러개의 카드를 선택

2. Thread Safe

  • Race Condition의 발생하는 이유는 스위프트가 Thread Safe하지 않다는 것
  • Thread Safe하다는 것은 여러 스레드에서 동시에 접근이 불가능 한 것을 말함

3. DispatchSemaphore

  • Race Condtion를 해결하기 위한 수단 중 하나
  • 공유 자원에 접근할 수 있는 스레드의 수를 제어해주는 역할
  • DispatchSemaphore는 semaphore count를 카운트 하는 방식으로 동작
let semaphore = DispatchSemaphore(value: 1) // count = 1

DispatchQueue.global().async {
	// wait로 스레드 값에 접근했음을 알림
    semaphore.wait() // count -= 1

	// signal로 스레드 실행 종료를 알림
    semaphore.signal() // count += 1
}

// 사용예

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()
    }
}

4. Serial Queue 활용

  • Race Condition 발생이유 -> 여러 스레드에서 질서없이 배열에 접근
  • 질서를 Serial Queue로 만드는 방식
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) 카드를 뽑았습니다!")
        }
    }
}
profile
Wooyo의 개발 블로그

0개의 댓글