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

Tae Kyoung Ha님의 프로필 이미지

작성한 질문수

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

1) 반드시 메인큐에서 처리해야하는 작업 2) sync메서드에 대한 주의사항 3) weak, strong캡처 주의 4)컴플리션핸들러의 존재이유 5) 동기적함수를 비동기함수 처럼 만드는 방법

GCD - 3.디스패치큐(GCD) 사용시 주의해야할 사항 교착 상태에 관한 질문입니다.

작성

·

192

1

안녕하세요 그래프로 큐-스레드 간 관계를 보기 좋게 정리해주셔서 직관적이고 이해하기 쉬워서 감사드리면서 수강하고 있습니다.

위 강의에서 설명해주신 교착 상태와 관련하여 질문이 있습니다.
강의 내용 내에서 play ground 교착 상태 예제 코드의 주석중

"본 예제는 작업시간이 워낙 짧기 때문에 실제 Deadlock(교착상황)이 안생길수 있다" 는 말씀이 이해가 잘 가지 않습니다.
결국 이 문장이 의미하는 바를 풀어쓴다고 한다면, "구조적으로는 교착상황임에도 불구하고, task의 수행 시간이 매우 짧아 실제로 교착 상황이 발생하지 않는다" 인것이 맞을까요?
만약에 그렇다고 한다면 아래 2가지의 궁금증이 생깁니다.

1. 제가 기존에 알고 있던 '교착 상황 '의 정의와 다릅니다.

제가 교착상태의 정의에 관하여 알고있는 바로는 각 스레드 및 프로세스간의 작업 시간 길이와는 상관없이, 각 스레드 및 프로세스가 자신의 task를 수행하기 위해서 서로 상대의 자원이 필요한 상황에빠져, 서로의 각자의 task 수행 자체가 불가능한 '무기한 연기' 상황에 처하는 것으로 알고 있습니다.
한 작업이 "상대의 작업이 끝나기를 기다리는 상황"이 아닌
"자신의 task 수행을 위해 서로가 상대의 자원을 요구하는 상황으로 무기한으로 task 수행 자체를 하지 못하는 상황"
으로  알고 있는데,
그렇다고 한다면 이는 스레드가 수행하는 task의 작업 시간이 짧은 것과는 어떤 연관이 있는 것인지 질문드립니다.

제가 교착 상황에 대한 정의를 잘못 이해하고 있는 부분이라면 교착 상황에 대해서 설명해주시면 감사드리겠습니다.

2. 1의 의문에 근거하여 생긴 추가 의문

1의 의문에 의해 강의에서 보여주신 예제 코드가 교착 상태가 아니라는 가정을 깔고 생각할 경우,  

DispatchQueue.global().async {

       var name: String {

         return DisaptchQeue.global().sync {

            "\(firstName)\(lastName)"

           }

        }

}

예제에서 언급해주신 위 형태의 코드는 단지 처음에  async 지정해주었던 task를 바로 다시 sync 로 지정해주는 것에 그치는 것이 아닌가(상대의 작업이 끝나기를 기다리는 상황) 라는 생각이 드는데요
1번 질문에 대한 답변이 된다면 2번 질문에 대한 답변은 저절로 될 것 같아 1번 질문만 답변 해주셔도 될 것 같습니다.

긴 질문글 읽어주셔서 감사합니다. 강의 재밌게 잘 듣고 있습니다.

답변 1

3

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

태경 님 강의에 대한 좋은 질문 감사드립니다. ^^

일단은.. 제가 주석을 좀 잘 못 적어 놓은 것 같습니다. 죄송하다는 말씀을 먼저 드립니다.

참고 목적으로 보시길 원해서, 처음에 주석을 그렇게 적어놓은 것인데.. 지나고보니, 헷갈릴 수 있는 완전히 잘못된 설명이네요ㅠ

네, 그래서 제가 좀 다시 정확하게 말씀드리면..

“본 예제는 작업시간이 워낙 짧기 때문에 실제 Deadlock(교착상황)이 안 생길 수 있으나, 구조 위주로 참고”가 아니고,

주석(또한 설명)이

“동시(Concurrent)큐이기 때문에 <항상> 교착 상황이 생기지는 않는 예제임(교착상황의 가능성을 내포하고 있음), 구조 위주로 참고”가 더 정확한 표현인 것 같습니다.

1)교착상태

먼저 위의 내용에 대해서, 설명 드리기 전에 

교착상태에 대한 정의를 먼저 설명 드리고, 위의 내용을 다시 설명 드려보도록 하겠습니다.

일단은 교착상태는 단순히 자원 뿐만아니라, 

이상의 작업이 서로 상대방의 작업이 끝나기 만을 기다리고 있기 때문에 결과적으로 아무것도 완료되지 못하는 상태 가리키는 조금은 폭넓은 개념입니다. , 자원의 사용/메모리 접근에 관한 문제뿐만아니라, 쓰레드 사용에 있어서도 block 일어난 쓰레드에 접근하여, 결과적으로 일처리가 전혀 진행되지 않는.. 그런 상황에서도 쓰이는 용어입니다. , 물론 태경 님께서 말씀해주신 자원에 관한 문제에서 주로 교착상태가 발생 한다고 합니다. (다만, 조금 폭넓은 의미가 있다는 것을 알아두시면 좋을 같습니다.)

2)예제상황

네 일단은 제 강의의 <GCD 3.주의해야할 사항 - 2) sync메서드에 대한 주의사항 12:50초 ~ 13:50초>의 설명을 조금 더 추가하자면,

DispatchQueue.global().async {

      DispatchQueue.global().sync {

      }

}

의 상황에서, 교착상태는 항상 발생하는 것은 아니지만, 때때로 발생할 수 있기때문에(또는 발생할 가능성을 내포하고 있으므로).. 이런 코드를 작성하면 안된다 라고 설명을 드려야 할 것 같습니다. 왜냐하면, 만약 어떤 “task1”이라는 작업을 비동기적으로 글로벌큐로 보내서.. 2번 쓰레드에 배치되어있다고 해보겠습니다. 그런데, 그 작업을 다시 동기적으로 글로벌큐로 보냈다고 해보겠습니다.

그러면, 원래 작업이 배치되었던 2번쓰레드는 “블락(block)”이 되어있고, 

해당 task1은 큐에 들어갔다가, 다시 작업이 배치가 될 것입니다.

그러면 그 상태에서.. 작업이 예를 들어 2번 또는 3번 또는 4번 쓰레드에 배치가 될 수 있습니다.

만약에 “task1”이 다시 2번 쓰레드에 배치가 되면, 교착상황이 발생합니다. 그런데, 2번 쓰레드가 아닌 3번이나, 4번 쓰레드에 배치가 되면 교착 상황이 발생하지 않습니다. ( 그림으로 표현 하자면 아래와 같습니다.)

그래서, 결론적으로 다시 말씀 드리자면 

“현재의 큐에서 현재의 큐로 작업을 동기적으로 보내면 교착상황이 발생할 수 있는 가능성을 내포하므로, 이런 처리를 하면 안된다”라는 것이 정확한 설명입니다.

그리고 이제 말씀하신 예제로 돌아와서 다시 정확한 설명을 드리면… 실은 예제의 작업 시간이 짧기 때문에 교착상황이 발생하지 않는 것이 아니고, 

동시큐이기  때문에 작업이 배치되는 과정에서 교착상황이 발생할 수도 있고, 안할수도 있다는 것이 더 정확한 설명입니다.

(만약에 동일한 직렬큐에서 동일한 직렬큐로 sync로  보내는 코드를 짜보시면, 실제 작업 시마다 교착상태가 발생하는 것을 확인해 보실 수 있을 것입니다.)

그러니까, 이 예제에서 

동시큐에서 동시큐로 for문을 통해 보내는 조합이니…

2번쓰레드에서 하던 작업이 2번쓰레드에 다시 배치 되어야 교착상황이 발생하고, 3번 쓰레드에서 하던 작업을 3번 쓰레드에 다시 보내야…. 교착상황이 발생하게 되는데..

확률적으로 5번의 for문 작업에서 한번 걸릴까 말까하게 발생할 것입니다.

3)  그리고 하단부 질문

DispatchQueue.global().async {

       var name: String {

         return DisaptchQeue.global().sync {

            "\(firstName)\(lastName)"

           }

        }

}

예제에서 언급해주신 위 형태의 코드는 단지 처음에  async 지정해주었던 task를 바로 다시 sync 로 지정해주는 것에 

그치는 것이 아니냐 부분에서는.. 

사실 핵심은, 2번쓰레드로 보냈다가, (2번쓰레드에서는 실제 블락하고 기다리는 일이 발생) 다시 다른 쓰레드로 재 배치하는 일이 실제로  발생한다는 것입니다.

즉, 블락하고 기다리는 쓰레드가 1번 쓰레드가 될 것이냐, 2번 쓰레드가 될 것이냐에 관한 사실이 바뀌는 것이 중요하게 작용합니다.

여기서는 작업이 한번 2번쓰레드로  보내졌기 때문에(aync)…  이제 여기서 다시 sync로 보내면,

1번 쓰레드가 아닌 2번 쓰레드가 자신을 블락(block)하고 기다리게 된다는 것이 핵심입니다. 

(이 부분은 제 강의를 더 듣으시다가, 실제로 심화편에서 sync메서드를 사용하는 부분이 나오는데.. 그때 더 정확하게 이해하게 되실 것이라는 것을 확신합니다 ^^;)

제 답변이 잘 이해가 가시길 바라고.. 사실 바로 전 질문(비슷한 질문)도 참고 하시면… 아마 이해가 되실 것이라고 생각됩니다.

 

글로 온전히 설명하는 것이 어려워서.. 혹시, 제 답변이 이해가 안되시면, 다시 질문 남겨주시면 다시 설명드려보도록 하겠습니다. ^^

그리고, 말씀해주신 내용을 반영해서.. 교안을 좀 수정해 놓아야 겠네요ㅜ 강의도 설명을 좀 더 추가해서 다시 찍고요 :)

강의를 재밌게 듣고 계신다니 영광일 따름입니다. 감사합니다 :)