[iOS] 차근차근 시작하는 GCD — 11

동시성과 관련된 문제들 (Concurrency Problems) 중 경쟁 상태(Race Condition)에 대해 알아봅시다

Previously on GCD…

대박대박대박버거~~~~ 개-하! (개발자들 하이라는 뜻)

이게 몇만년만의 GCD람요~~!! 사실 글 초안은 좀좀따리 써놨었는데 주제가 주제인지라.. ㅎㅎㅎ 기약 없이 미루다보니 벌써 두달이 지났네유 ◠‿◠ .. ㅎㅎ (사실 저는 예전에 강의도 다 들음여~~!!) 튼 아무래도 글이 길어지면 더 안쓰게 되는 것도 있는거 같아서 끊어 쓰려고요 ㅎ

저번 시간에는 DispatchSemaphore에 대해 다뤘는데 ㄱ나니..? (아련) 흠 사실 저도 안난답니다!

당-당

하지만 괜찮아여 기억 안나는건 또 보면 되는거고 오늘은 새로운 마음가짐으로 동시성 문제를 다룰거니까여~~ 그럼 각설하고 고고링~!

동시성 문제 (Concurrency Problem)

우리는 2강? 3강?에서 concurrency 의 개념을 배운 이후로, 작업을 여러개의 스레드에서 처리할 수 있다는 걸 알고 내용을 진행해왔슴다.

컨커런시에서는~~ 다 같이~ 사이좋게~ 일을 합시다~~!!~ 스레드는 잘도 도네 돌아가네~~

그런데 이런 Concurrency 상황에서 발생할 문제점에 대해 생각해 보신적 있으신가여? 없어도 괜찮아요. 지금부터 알아보면 되니까여 ㅇㅇ! 그림을 한번 봅시다.

서로 접근하려고 함~~~

여러개의 스레드에서 공유 자원을 동시에 접근하고 있군요!! 이러한 상황에서 발생할 수 있는 문제가 바로 “동시성 문제”인데요, 바로

두 개 이상의 스레드를 사용하면서, 동일한 메모리 접근 등으로 인해 발생할 수 있는 문제

라고 이해하시면 됩니다.

동시성 문제는 크게 아래의 세가지 케이스가 있는데요!

  1. Race Condition (경쟁 상태)
  2. Deadlock (교착상태)
  3. Priority Inversion (우선 순위의 뒤바뀜)

이번 시간에는 Race Condition (경쟁 상태)이 무엇인지와 해당하는 케이스를 살펴보도록합시다. 해결 방법은? 다음 시간에~

Race Condition (경쟁 상태)

우선 위키피디아에서 경쟁 상태를 어떻게 정의하는지 검색해봅시다.

경쟁 상태공유 자원에 대해 여러 개의 프로세스가 동시에 접근을 시도할 때 접근의 타이밍이나 순서 등이 결과값에 영향을 줄 수 있는 상태를 말한다. 동시에 접근할 때 자료의 일관성을 해치는 결과가 나타날 수 있다.

오키오키 공유 자원에 여러개의 프로세스가 동시에 접근하면 값이 예상과 다르게 변할 수 있어서 문제가 된다는거군 ㅇㅇ (엄밀히 말하면 동시에 읽기는 노 상관)

우리의 상황에서는 프로세스를 스레드로 바꿔서 이해하면 되겠쥬?

그래서 진짜로 값 변경이 예상대로 동작하지 않는지 확인하기 위해 여러개의 스레드에서 공유 자원 (sharedValue )에 접근하는 코드를 작성해봤어요!

결과는 어떻게 될까요?? 여러분이 어떤 값을 예상하셨는진 모르겠지만.. ! background after 과 userInteractive after 값만 살펴보자면 돌릴때마다 200, 100 / 100, 200 / 100, 100 / 200, 200 등 다양한 결과가 나왔답니다.

userInteractive after 200
background after 100
final: 100
// 아마도 여러분이 예상한 결과?
background after 100
userInteractive after 200
final: 200
userInteractive after 100
background after 100
final: 100
background after 200
userInteractive after 200
final: 200

이게 도대체 어떻게 된 상황인지 자세히 살펴보기 위해 우선 각각의 상황을 taskA와 taskB로 재정의 해볼게요

  • taskA write: userInteractive Queue에서 sharedValue200을 씀
  • taskA read: userInteractive Queue에서 sharedValue 를 읽음
  • taskB write: background Queue에서 sharedValue100을 씀
  • taskB read: background Queue에서 sharedValue 를 읽음

각 task 의 read와 write가 동시에 발생하면 아주 골치 아파질거라는게 예상이 가시나요? taskA read — taskB write or taskA write — taskB read 이런 조합으로 말이에여.

한쪽에서는 쓰라고 하고, 한쪽에서는 읽으라고 하고.. 뭐 어쩌라고?! 상황이 되는거죠

그럼 아까의 다양한 출력 케이스가 어떻게 나오게 된건지 그림으로 더 자세히 살펴볼까유?

taskA read — taskB write
taskA write — taskB read

아주 난리도 이런 난리가 없네여!

각 task 가 아주 동시에 sharedValue에 접근해서 지들이 원하는 동작만 하겠다고 난리니 문제가 발생하고 있습니다.

즉, 여러 스레드가 경쟁적으로 공유 데이터에 접근해서 읽기 및 쓰기를 하고 있기 때문에 예상치 못한 결과가 나오게 되는 것이죠!

이거시 바로 경쟁상태! 경쟁 상태의 정의를 다시 가져와서 읽어보아아요!

경쟁 상태공유 자원에 대해 여러 개의 프로세스 (우리는 스레드) 가 동시에 접근을 시도할 때 접근의 타이밍이나 순서 등이 결과값에 영향을 줄 수 있는 상태를 말한다. 동시에 접근할 때 자료의 일관성을 해치는 결과가 나타날 수 있다.

오키오키? 자료의 일관성 아주 단단히 해치고 있쥬?

그럼 이제 경쟁 상태를 해결하는 방안을 알아봐야겠네요! 스포 하자면 자원에 다수의 스레드가 접근해서 문제가 되는거니까 한번에 한개의 스레드만 접근 가능하도록 처리하면 될거예요! (Thread-safe)

후.. 그거 쓰려다가 엄두가 안나서 지금까지 미뤄온거긴 한데….. 언젠가…. 또 돌아오도록 하겠습니다! 그럼 20000!

이전 포스팅 👈🏻

다음 포스팅 👉🏻

출처

 https://github.com/sujinnaljin/TIL