동시성
여러 작업을 동시에 실행되는 것 처럼 보이게 하는 것
프로그램 / 프로세스 / 스레드
프로그램
- 단순한 코드 덩어리
프로세스
- 프로그램이 실제로 실행되어 메모리에 올라가 실행 중인 것
스레드
- 프로세스 내에서, 프로세스의 자원을 이용해서 실제로 작업을 수행하는 것
멀티 프로세스
멀티 프로세스
- 하나의 운영체제에서 동시에 프로세스를 여러개 실행시킬 수 있는 기술
멀티 프로세스 환경에서의 메모리 구조
- 하나의 운영체제에서 여러 프로세스들이 각각의 독립적인 공간을 할당받음
- 하나의 프로세스 내부에 코드, 데이터, 힙, 스택 영역들이 각각 존재
멀티 스레드
멀티 스레드
- 하나의 프로세스 내에서 둘 이상의 스레드가 동시에 작업을 수행하는 것
멀티 스레드 환경에서의 프로세스의 메모리 구조
- 하나의 운영체제에서 여러 프로세스들이 각각의 독립적인 공간을 할당받음
- 하나의 프로세스 내부에 코드, 데이터, 힙, 스택 영역들이 각각 존재
- 코드, 데이터, 스택 영역은 컴파일 시 메모리 크기가 결정됨 >> 정적할당
- 힙 영역은 런타임 시 크기가 결정됨 >> 동적할당
- 코드, 데이터, 스택의 경우 메모리 주소값이 낮은 주소값부터 할당
- 스택의 경우 높은 주소값부터 할당맏음
- 힙과 스택 영역은 서로 공유
- Stack 영역의 메모리 주소값이 지나치게 할당되어 Heap 영역을 침범하는 것을 Stack Overflow
- Heap 영역의 메모리 주소값이 지나치게 많이 할당되어 Stack 영역을 침범하는 경우엔 Heap Overflow
동시성 이슈
- 한 프로세스 내에서 여러 스레드들이 동시에 동작하면서 발생하는 문제들
- Race Condition, Deadlock, Starvation, Priority Inversion 등
1. Race Condition
여러 스레드들이 같은 공유 자원(데이터)에 접근해서 결과값에 영향을 줄 수 있는 상태
1-1. 해결방법
상호배제를 통해 공유 자원에 하나의 스레드만 접근할 수 있도록 설계
1-2. Mutex
- 공유 자원에 접근하는 스레드들에게 lock이라는 bool type의 변수를 통해 권한을 주고, lock을 취득한 스레드만 자원에 접근할 수 있도록 하는 방법
- 위의 스레드들은 lock이 해제될 때까지 반복문을 통해 기다리는데 이를 Spinlock 이라고함
Spinlock
- 대기 순서 보장 X
- 결국 공유자원에 접근하지 못하는 스레드가 발생할 가능성이 있기에 동시성 이슈인 Starvation 문제 발생 가능
1-2. Semaphore
- 공유자원에 접근할 수 있는 스레드의 개수를 Semaphore라는 Interger 변수로 관리하는 기법
- Semaphore가 0 --> 공유 자원에 더이상 접근 불가능, 접근하지 못하는 스레드들은 대기큐에서 관리 --> Starvation 문제 XX
- Semaphore가 1 --> 공유자원에 하나의 스레드만 접근하기 때문에 문제 일어나지 않음
- Semephore가 2 이상 --> 결국 여러 스레드가 하나의 공유 자원에 접근해서 값을 변경할 수 있기 때문에 Race Condition 문제 발생
1-3. Binary Semaphore
Semaphore 특성은 그대로 가져가되, Semephore를 이진수의 Binary 형태로 관리하기 때문에 스레드가 한 개만 접근이 가능, 고로 Race Condition 문제가 일어나지 않음
2. Deadlock
교착 상태, 두 개 이상의 작업이 서로 끝나기만을 기다리는 상태
2-1. Deadlock 발생 조건
상호배제
공유자원에 하나의 스레드만 접근 가능해야함
점유대기
자원을 하나 보유한 상태에서, 다른 스레드에 할당된 자원을 점유하기 위해 대기하는 상태
비선점
다른 스레드에게 할당된 자원을 강제로 빼앗을 수 없음
순환대기
대기하는 스레드들의 집합이 순환형태로 자원을 대기
2-2. Deadlock 해결 방법
예방
데드락 발생 조건 중 1개를 발생시키지 않도록 설정
회피
은행원 알고리즘을 통해 데드락 발생 가능성에 대해 예측하고, 발생 가능성이 있다고 하면 요청 거절
탐지 / 복구
- Deadlock 허용하지만, 데드락 발생 여부를 지속적으로 탐지
- 데드락이 발생하면 Deadlock Recovery 방식을 통해 Deadlock을 회복
무시
- 아무처리 X
- 해결하는 데 드는 Resource가 크기 때문에, 무시를 제일 많이 채택
동시성 이슈 해결 방법
1. GCD
1.1 DispatchQueue.sync
sync 보낼 시, Thread 1개가 보장되므로 해결 가능
1.2 Dispatch Barrier
- 병렬 실행큐에서 작업을 순차적으로 실행하도록 보장, 이전 작업이 완료될때까지 다른 작업 차단
- 읽기 작업과 쓰기 작업을 분리해 동시성 제어
let concurrentQueue = DispatchQueue(label: "com.example.concurrent", attributes: .concurrent)
concurrentQueue.async {
print("읽기 작업 1")
}
concurrentQueue.async {
print("읽기 작업 2")
}
concurrentQueue.async(flags: .barrier) {
print("쓰기 작업 - 순차적으로 실행")
}
1.3 NSLock
- Mutex 와 동일한 기법으로, 앱 내에서 여러 실행 스레드의 작업 조정하는 객체
- lock(berfoer: Date:) : 특정 시점까지 lock을 획득하도록 시도하는 메서드
- unlock() : lock을 해제하여 다른 스레드가 접근할 수 있도록 설정
- try() : lock을 획득할 수 있는지 시도하는 메서드
let lock = NSLock()
func criticalSection() {
lock.lock()
// 보호할 코드
print("Thread-safe 작업 실행")
lock.unlock()
}
1.4 DispatchSemaphore
- semaphore와 동일한 기법, 공유자원에 접근할 수 있는 스레드 개수 지정
- wait() : semaphore 변수를 감소 메서드
- signal() : semaphore 변수 증가 메서드
let semaphore = DispatchSemaphore(value: 1)
DispatchQueue.global().async {
semaphore.wait() // 리소스 접근 허용 대기
print("Thread-safe 작업 실행")
semaphore.signal() // 리소스 해제
}
2. Swift Concurrency
이 친구는 이후 포스트에 적어보겠습니다~
Coming Soon ~
.
.
.
.
'Swift' 카테고리의 다른 글
[iOS] About 채팅 UI (0) | 2024.11.20 |
---|---|
[iOS] About Local Notification (0) | 2024.11.13 |
[iOS] About WidgetKit - 2(App Group) (0) | 2024.11.02 |
[iOS] About TDD (1) | 2024.10.30 |
[iOS] About Notification & Delegation (0) | 2024.10.26 |