인프런 커뮤니티 질문&답변

김기현님의 프로필 이미지
김기현

작성한 질문수

앨런 iOS Concurrency(동시성) - 디스패치큐와 오퍼레이션큐의 이해

GCD - 7.(심화) Thread-safe한 코드의 구현과 방법 / 2)시리얼큐와 Sync 에서 질문입니다.

해결된 질문

작성

·

538

1

안녕하세요 강사님! 

해당 강좌를 듣다가 제가 이해한 것이 맞는지 궁금해서 질문드립니다.

제가 이해한 내용을 아래와 같이 정리해봤는데 혹시 피드백을 주실 수 있을까요?

동시큐 등에서 접근할 가능성이 있는 객체 설계시

ViewController 부분(1차 호출 부)

DispatchQueue.global().async{
 count = count + 1 // task1
 count = count + 2 // task2
 count = count + 3 // task3
}

객체 부분

private let serialQueue = DispatchQueue(label: "...")
private var _count = 0
public var count: Int{
get{
    return serialQueue.sync{ // serial Queue에 넣었으면 됐지, 왜 또 async가 아닌 sync 일까?
        _count
       }
   }
set{
    serialQueue.sync{
        _count = newValue
       }
   }
}

위의 코드를 그림으로 표현하면 다음과 같은 형태가 됩니다.

뷰컨트롤러에서 concurrentQueue에서 async로 객체의 serialQueue로 async 로 접근하는 모습입니다.

이를 더 자세하게 표현하자면 아래와 같습니다.

1. Thread1 에서 Queue(DispatchQueue.global())에 task들이 들어간다.

각각의 task들은 async로 되어있기 때문엔 Thread1에서는 block 되는 작업 이없다.

2. 각각의 task들은 thread2, 3, 4 에 배정된다.

3. 각각의 task들은 SerialQueue에 들어가게 되는데 이는

sync 메서드를 사용했기 때문에 block 처리되어서 serialQueue에 들어가게 된다.

4. SerialQueue에서 순서대로 Thread5에 배정되어 task가 처리된다.

5. 예상되는 count값은 6 이다.

감사합니다.

답변 7

1

김기현님의 프로필 이미지
김기현
질문자

감사합니다 ㅎㅎ

강의와 올려주신 코드를 다시한번 보니 이제 정말 완벽하게 이해했습니다 ㅎㅎ

늦은 시간임에도 불구하고 답변달아주셔서 정말 감사합니다. 덕분에 항상 많이 배워갑니다.

즐거운 주말보내세요! :)

1

앨런(Allen)님의 프로필 이미지
앨런(Allen)
지식공유자

아 네..

기현님  말씀처럼, 동시큐에서는 그렇게 묶이지만,

작업이 다시 시리얼큐로 가니.. 그때 작업이 나눠져서 구성된다고 말씀을 드려야 겠네요.

(시리얼큐로 보내지면서 쓰레드에 접근하는 기준으로 다시 나눠짐)

즉, 아래와 같은 식이라고 해야할까요?

네 일단 위와 같은 방식이고,

제 수업자료에서도 비슷하게 아래와 같은 내용을 다루고 있긴합니다 ^^

혹시나.. 헷갈리실 까봐 자료를 안  올리긴 했는데..

https://drive.google.com/open?id=1Z-UNQhkXISbptRRsW-3eHcy11kTY6K6_

위의 링크에서 프로젝트를  다운 받으셔서 기현 님 예제와 동일한 예제를

프린트로 찍어보는 내용을 담아보긴 했습니다.

프린트로 직접 찍어보시면 읽기/쓰기가 어떻게 일어나는지 보실 수 있어요ㅎㅎㅎ

혹시나 참고가 되시길 바랄께요 ^^

감사합니다.  :)

1

김기현님의 프로필 이미지
김기현
질문자

제가 수정을 눌러서 답변이 꼬인 것 같네요 ㅠ 죄송합니다. 다시 질문을 드리겠습니다 ㅎㅎ

한가지 궁금한건 

[읽기 + 읽기 + 쓰기 +  쓰기 + 읽기 + 쓰기] 이런  식으로  뒤죽박죽이 될 가능성이 농후합니다.  라고 답변달아주셨는데

count부분을 async로 접근하지만( DispatchQueue.global().async{ } ) count 자체는 SerialQueue.sync{} 로 되어있기 때문에 

순서를 보장할 수 있다라고 저는 이해했는데 틀린 부분이 있을까요?

즉, 다시말해 [task2(읽기 + 쓰기) + task3(읽기 +  쓰기) + task1(읽기 + 쓰기)]  이런식으로 task 자체는 async로 뒤죽박죽이지만 읽기 쓰기 작업은 serialQueue에서 sync로 동작하는 것을 이해하고 있었습니다!

항상 빠르고 친절한 답변 감사합니다!

1

김기현님의 프로필 이미지
김기현
질문자

빠르고 친절한 답변 감사합니다!

오랜만에 강의를 들어서 기초부분을 깜빡했는데 다시한번 짚어주셔서 감사합니다 ㅎㅎ

한가지 궁금한건 

[읽기 + 읽기 + 쓰기 +  쓰기 + 읽기 + 쓰기] 이런  식으로  뒤죽박죽이 될 가능성이 농후합니다.  라고 답변달아주셨는데

count부분을 async로 접근하지만( DispatchQueue.global().async{ } ) count 자체는 SerialQueue.sync{} 로 되어있기 때문에 

순서를 보장할 수 있다라고 저는 이해했는데 틀린 부분이 있을까요?

즉, 다시말해 [task2(읽기 + 쓰기) + task3(읽기 +  쓰기) + task1(읽기 + 쓰기)]  이런식으로 task 자체는 async로 뒤죽박죽이지만 읽기 쓰기 작업은 serialQueue에서 sync로 동작하는 것을 이해하고 있었습니다!

항상 빠르고 친절한 답변 감사합니다!

1

앨런(Allen)님의 프로필 이미지
앨런(Allen)
지식공유자

안녕하세요 기현님 ^^

일단은 하단의 논리적인 흐름정확하게 이해하신게 맞습니다.

다만,  그림처럼 동시큐에서 여러 쓰레드를 사용하는 상황을 가정하시려면

이렇게 설정하시면 안되고,

아래처럼 되어야 합니다.

왜냐하면,

async  다음의 클로저의 {  } (중괄호)는 작업을 하나로 묶는 역할을 합니다. 그래서 여러 쓰레드를 사용 하는 상황을 가정하시려면, 바로 위의 코드 처럼 되어야 합니다.

이 부분은

제 강의자료에서 GCD코드부분 1-1.SimpleExample페이지에서 아래의 자료를  다시한번 참고해보시면 좋을 것 같습니다.

동시큐로 작업을 나눠서 구성하시고, 여러 쓰레드로 보내는  실험 프로젝트를 한개 만들어 보실 수 있을 것 같아요!

그런데, 참고적으로 말씀을 드리면,

그렇게 구성을 하시면, 아마 count 속성에서 6의 값을 얻기는 조금 어려우실 꺼예요.

왜냐하면, 가정하신 상황에서 6을 얻으시려면 가정하신 작업의 특성상 읽고 쓰는 일이 순차적으로  일어나야만 합니다.

그러면, 시리얼큐로 보낸다 하더라도 (동시큐에서 시리얼큐로) 보내는 순서가

[읽기 + 쓰기 +읽기 + 쓰기 + 읽기 + 쓰기]로 구성이 되어야  하는데,  보내는 큐가 동시큐 이기 때문에

[읽기 + 읽기 + 쓰기 +  쓰기 + 읽기 + 쓰기] 이런  식으로  뒤죽박죽이 될 가능성이 농후합니다.

따라서, 이런  count  = count  + 1 작업처럼 작업자체가 순차적으로 구성되어야하는 경우(자체가 시리얼이 필요한 작업)가 아닌 경우를 케이스로 만들어서 실험해보시면 보다 좋을 것 같습니다.

논리적인 내용은  정확하게 이해하셨습니다. ^^

혹시 추가적으로 질문이 있으시면 올려주세요.

감사합니다. :)

0

앨런(Allen)님의 프로필 이미지
앨런(Allen)
지식공유자

아이고 아닙니다. 제가 감사드리죠!!ㅎㅎ 주말 늦은 시간에도 이렇게 열심히 공부를 하시는 ㅎ_ㅎ

기현 님도 좋은 주말 되세요 :)

0

앨런(Allen)님의 프로필 이미지
앨런(Allen)
지식공유자

정확하게 이해하셨다니 다행이네요! 적극적으로 질문도 올려주시고.. 정말 고맙습니다. :)

김기현님의 프로필 이미지
김기현

작성한 질문수

질문하기