inflearn logo
강의

講義

知識共有

アラン iOS Concurrency(並行処理) - Dispatch QueueとOperation Queueの理解

Barrier 작업 관련 질문입니다.

340

rladudrbs012949

投稿した質問数 1

1

안녕하세요! 본강의 Barrier파트를 듣고 직접 구현을 해보았을때, 모르는 부분이 생겨 질문을 드립니다.

 

barrier 작업들을 DispatchGroup으로 묶었을 경우

Tsan을 체크하고 빌드하는 경우 Thread-Safe하지 않는 부분이 감지되었습니다.

반면, 똑같은 barrier 작업을 DispatchGroup으로 묶지않는 경우는

Tsan에 감지되지 않는데, 이런 결과가 나오는 이유를 모르겠어서 질문드립니다!

// Tsan에 감지되는 코드(DispatchGroup)

for i in 1...5 {
    print("--- \(i)번째 ---")

    let group = DispatchGroup()

    var someNumber = 10

    DispatchQueue.global().async(group: group, flags: .barrier) {
        sleep(1)
        someNumber *= 10    // Race Condition 감지되는 부분
        print("after multiple 10 : \(someNumber)")
    }

    DispatchQueue.global().async(group: group, flags: .barrier) {
        sleep(1)
        someNumber += 1     // Race Condition 감지되는 부분
        print("after add 1 : \(someNumber)")
    }

    group.notify(queue: .main) {
        print("\(i)번째 결과 : \(someNumber)")
    }

    group.wait()
}
// Tsan에 감지되지 않는 코드(DispatchGroup X)

for i in 1...5 {
    print("--- \(i)번째 ---")

    var someNumber = 10

    DispatchQueue.global().async(flags: .barrier) {
        sleep(1)
        someNumber *= 10
        print("after multiple 10 : \(someNumber)")
    }

    DispatchQueue.global().async(flags: .barrier) {
        sleep(1)
        someNumber += 1
        print("after add 1 : \(someNumber)")
    }
}

swift ios

回答 1

0

allen

안녕하세요 코코 님!

조금 잘못 실험하신 부분이 있으신 것 같은데요,
제 경우엔 위아래 코드가 다 경쟁상황에 걸립니다. 디스패치 그룹 여부와는 상관이 없습니다.


그리고, 장벽작업을 사용하시려면 디폴트큐를 사용하시면 안되고,
직접 큐를 커스텀으로 만드신 다음에 하셔야합니다.


var concurrentQueue = DispatchQueue(label: "label", attributes: .concurrent)

var someNumber = 10
        
for i in 1...5 {
     print("--- \(i)번째 ---")

     concurrentQueue.async(flags: .barrier) {
          sleep(1)
          someNumber *= 10
          print("after multiple 10 : \(someNumber)")
     }

     concurrentQueue.async(flags: .barrier) {
          sleep(1)
          someNumber += 1
          print("after add 1 : \(someNumber)")
     }
}

이런식으로 먼저 커스텀큐를 만드신 다음 장벽 작업으로 보내시면 됩니다.

그리고, 아무래도 실험을 하시려는 것이면.. someNumber 변수를 for문 내부가 아닌 바깥에 선언하시는 것이 맞을 것 같아서, 위처럼 실험을 해보시면 될 것 같네요!

잘 동작을 합니다.


감사합니다. :)

 

0

rladudrbs012949

image

customQueue로도 해보았을때 위의 사진처럼 Tsan으로 빌드하는 경우 감지되었습니다.

 

추가적으로 someNumber을 바깥으로 보냈을때도, 문제가 발생하였습니다. ㅠㅠ

0

allen

(그룹이 왜 for문 안에 들어가 있는 것일까요? 저건 계속 새로운 그룹 객체를 생성하는 코드 입니다. 코드가 잘못되셨어요. 그룹도 당연히 for문 밖으로 빼셔야 겠죠....)

그럼에도 불구하고,
비동기로 보낼때, 장벽작업(barrier)과 디스패치 그룹(dispatch group)을 같이 사용했을때, 내부적으로 뭔가 잘못동작하는 것이 있는 것 같네요.

내부적으로 돌아가는 어떤 메커니즘이 있는 것들을.. 제가 다 파악하기는 힘듭니다. 저도 검색을 해봤지만, 특별하게 이런 내용에 대해서 나와있는 것도 없고, 공식문서에도 이와 관련된 내용도 기술되어 있지 않네요. (구글링해서 찾게 되시면 저도 좀 알려주세요.)

정말 원하시는 것이 디스패치 그룹을 사용하고 싶으신 것이면, 다른 방식으로 문제를 해결하면 되시지 않을까 합니다. 디스패치 그룹에 있는 enter / leave를 사용하시면 Thread-safety 문제없이 일단 원하시는 대로 동작하기는 합니다.

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        checkRace()
    }
    
    var concurrentQueue = DispatchQueue(label: "label", attributes: .concurrent)
    var someNumber = 10
    let group1 = DispatchGroup()
    
    func checkRace() {
        
        for i in 1...5 {
            print("--- \(i)번째 ---")
    
            self.group1.enter()
            concurrentQueue.async(flags: .barrier) {
                sleep(1)
                self.someNumber *= 10
                print("after multiple 10 : \(self.someNumber)")
                self.group1.leave()
            }
            
            self.group1.enter()
            concurrentQueue.async(flags: .barrier) {
                sleep(1)
                self.someNumber += 1
                print("after add 1 : \(self.someNumber)")
                self.group1.leave()
            }
        }
        
        group1.notify(queue: DispatchQueue.global()) {
            print("끝")
        }
    }
}

감사합니다.. :)

오퍼레이션 큐 질문

0

128

2

2) 오퍼레이션큐(OperationQueue) 강의 질문입니다

0

145

2

warning 뜸

0

151

1

수업자료 markup 에 대해 궁금합니다!

0

273

1

예제 프로젝트 빌드 실패

0

331

2

serial 큐 질문드립니다.

0

251

1

[7-3.DispatchBarrier] 예제 코드 질문

0

325

1

안녕하세요, GCD 관련 질문드립니다..

0

284

1

main.async 작동 질문(+ vs global(),async)

0

432

1

dismiss 되었을 때 종료질문

0

303

1

'동기'와 '동시성 프로그래밍'에 대해 질문드립니다.

0

491

2

Dependency Protocol 관련

1

364

1

시리얼 큐와 sync 관련

0

464

2

sync이지만 Queue에 넣으면 async로 동작한다는 말의 의미

0

645

1

lazy var 이슈로 생긴 여러 변수들은 어디에 있나요?

0

385

1

global큐에 sync로 작업을 보냈을 때는 터지지 않는 이유가 궁금합니다.

1

501

2

비동기 개념에서 무엇을 return하는 거죠??

0

391

1

안녕하세욤

1

339

1

디스패치 그룹

1

381

1

global async안에 global async를 만들게되면 어떻게 되나요??

2

379

2

동기적 함수를 비동기적 함수로 바꾸는 부분에서 질문 있습니다

1

285

2

비동기오퍼레이션 관련 질문

1

369

1

강의자료는 어디에 있나요?

1

321

1

AsyncOperation을 async await Task로 대체 가능한 지에 대한 질문

1

410

1