Thread 문제의 특징

1. Race Condition(경쟁상황)

아래와 같은 코드가 있다고 생각해보자.

var a = 1

DispatchQueue.global().async {
	sleep(1)
	a += 1
}

DispatchQueue.global().async {
	sleep(1)
	a += 1
}

print(a)

위의 코드에서 print(a)는 무엇을 출력할까?

정담은 1이다.

그러나 여기서 정답이 중요한게 아니라 스레드에서 동시에 a에 접근하여 값을 write하는게 문제인 것이라서 아래의 그림을 더 참고해보도록 하자.

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/80649ce4-b60e-4148-8a89-9501d4ce2b28/Untitled.png

위의 그림처럼 Thread2, Thread3에서 동시에 하나의 자원에 접근할 때, 메모리에 있는 변수 a에 값을 쓸 수 있는데, 동시에 접근하였을 때의 문제를 위 그림은 아주 잘보여주고 있다.

Thread2에서 read하여 값1이고, 이후 순서가 Thread3에서 a 값을 read하여 값1을 읽어 왔다. 그리고 Thread2에서 1을 증가시켜 2가 되었다. 근데 Thread3에서는 이미 1로 알고 있던 a의 값이 2가 되었다. 그런데 여기서 1을 증가시키는 것이다. 이것은 개발자의 의도가 어찌되었던, 예기치 못한 문제가 발생한 상황이다.

이런 상황은 OS의 스케줄링 방식에 따라 얼마든지 결과값이 바뀔 수 있기 때문에, 이에 의존하기 보다는 공통으로 접근하는 자원에 대해서는 적어도 개발자가 통제 가능한 영역에 놓아야한다.

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/c2f571be-b04d-48b4-a34b-1d35d2224d31/Untitled.png

2. Deadlocks(교착상태)

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/f66fb3ba-1529-421e-8b58-d2a01f11838e/Untitled.png

Thread2에서 메모리 a에 접근하고 있고, 코드 내부적으로 잠금장치 걸었다고 쳐보자. 그 상태에서 Thread3에서 메모리 b에 접근하고 있고, 내부적으로 잠금이 걸렸다고 생각해보자.

이 상황에서, Thread2에서 b에 접근해야하거나 Thread3에서 a에 접근해야하는 상황이 오게 되면 앱이 더이상 진행이 안되고 멈추게 되는 현상을 교착상태라고 한다.