동시성
어떤 두 사건이 같은 시간에 일어나는 것
대부분의 웹 서버는 여러 개의 요청을 동시에 수행할 수 있고, 이는 작성한 코드가 동시에 수행될 수 있다.
프로그래밍을 하다 보면 이러한 동시성 처리가 필요한 경우가 있다.
하지만 동시성과 병렬성이 혼돈되어 사용되는 경우가 있어 한 번 정리해볼까한다.
동시성 vs 병렬성
| 동시성(Concurrency) | 병렬성(Parallelism) |
| 동시에 실행되는 것 같이 보이는 것 | 실제로 동시에 여러 작업이 처리되는 것 |
| 싱글 코어에서 멀티 스레드를 동작시키는 방식 | 멀티 코어에서 멀티 스레드를 동작시키는 방식 |
| 한 번에 많은 것을 처리 | 한 번에 많은 일을 처리 |
| 논리적인 개념 | 물리적인 개념 |
그림은 싱글 코어와 멀티 코어에서 동작하는 모습을 비교하는 그림이다.

싱글 코어에서는 2개의 작업을 동시에 실행되는 것처럼 보이기 위해 번갈아 가면서 작업을 수행한다.
이때, 다른 작업으로 바꾸어 실행할 때 내부적으로 Context switch가 일어난다
자세한 문맥교환은 다른 페이지에서 다루도록 하겠다.
그렇다면 우리가 동시성 이슈를 해결해야하는 이유는 무엇일까 ?
진행했던 프로젝트가 실제 적용될 수 있는 사례와 유사하니 이로 예시를 들어보겠다.
수량이 마지막 1개가 남아있는 시점에서 동시에 두 명의 유저가 요청을 하게 되었을 때 동시성 이슈가 해결되지 않을 경우, 둘 모두 성공하여 수량은 1개인데, 가져야 하는 사람이 2명인 난감한 상황이 펼쳐지게 된다. 이와 같은 상황에서 둘 모두 성공하는 것이 아니라 한 명만이 성공해야 하기때문에 동시성 이슈를 해결해야 한다.
위와 같은 상황을 경쟁 조건(race condition)이라고 한다.
경쟁 조건
여러 프로세스 및 스레드가 동시에 동일한 데이터(공유 데이터)를 조작할 때 타이밍이나 접근 순서에 따라 예상했던 결과가 달라질 수 있는 상황을 의미한다.
동시성 이슈의 문제점
- 공유 데이터에 대해 예상 결과가 다르지만 오류가 발생하지 않는다.
- 코드를 작성할 때는 로컬에서 개발하기때문에 파악하기 힘들다.
- 비정형적으로 발생하기때문에 디버깅이 힘들 수 있다.
동시성 이슈를 해결하면서 주의사항
뮤텍스, 세마포어, Lock 과 같은 경우 상호 배제만 해결해주기때문에 교착상태와 기아상태를 발생할 수 있다.
기아상태 (Starvation)
특정 프로세스의 우선 순위가 낮아서 원하는 자원을 계속 할당 받지 못하는 상태를 말한다.
교착상태
교착상태(Dead Lock)은 둘 이상의 프로세스들이 자원을 점유한 상태에서 서로 다른 프로세스가 점유하고 있는 자원을 요구하며 무한정 기다리는 현상을 의미한다.
기아상태와 교착상태의 차이
교착상태는 프로세스가 자원을 얻지 못해 다음 처리를 하지 못하는 상태를 말하고,
기아상태는 프로세스가 원하는 자원을 계속 할당 받지 못하는 상태이다.
즉, 교착 상태는 여러 프로세스가 동일한 자원 점유를 원할 때 발생하고,
기아 상태는 여러 프로세스가 자원을 점유하기 위해 경쟁할 때 특정 프로세스는 영원히 자원 할당을 받지 못하는 것이다.
교착 상태 발생 조건
주로 멀티 프로그래밍 환경에서 한정된 자원을 얻기 위해 서로 경쟁하는 상황에서 발생한다.
교착상태가 발생하기 위해서는 다음의 4가지 조건이 충족되어야 하는데, 이 네가지 조건 중 하나라도 충족되지 않으면 교착상태가 발생하지 않는다.
- 상호 배제(Mutual Exclusion)
자원은 한 번에 한 프로세스만이 사용할 수 있어야 한다.
상호 배제 기법에는 뮤텍스, 세마포어 등이 있다.
이 방법들은 상호 배제만 해결해주기 때문에 데드락과 기아상태가 발생할 수 있다.
- 뮤텍스
- Key에 해당하는 어떤 오브젝트가 있으며 이 오브젝트를 소유한 (스레드, 프로세스) 만이 공유자원에 접근할 수 있다.
- 임계영역을 가진 스레드들의 실행 시간이 서로 겹치지 않고 각각 단독으로 실행되도록 하는 기술
- 뮤텍스 객체는 제어되는 섹션에 하나의 스레드만 허용하기때문에 해당 섹션에 접근하려는 다른 스레드들을 강제적으로 막음으로써 첫 번째 스레드가 해당 섹션을 빠져나올 때까지 기다리도록 한다
- 세마포어
- 멀티 프로그래밍 환경에서 공유된 자원에 대한 접근을 제한하는 방법
- 현재 공유자원에 접근할 수 있는 스레드, 프로세스의 수를 나타내는 값을 기반으로 한다
- 세마포어는 공유 리소스에 접근할 수 있는 최대 허용치만큼 동시에 사용자 접근을 할 수 있게 한다.
- 스레드들은 리소스 접근을 요청할 수 있고, 세마포어에서는 카운트가 하나씩 줄어들게 되며 리소스 사용을 마쳤다는 신호를 보내면, 세마포어 카운트가 하나 늘어나게 된다.
- 이때 세마포어에서 발생할 수 있는 단점은 DeadLock 교착상태이다
- 모니터
뮤텍스와 세마포어의 차이
- 세마포어는 뮤텍스가 될 수 있지만, 뮤텍스는 세마포어가 될 수 없다.
- 세마포어는 소유할 수 없으며, 뮤텍스는 소유할 수 있고, 소유주가 그에 대한 책임을 가진다.
- 세마포어는 동기화 대상이 여러 개일때 사용하고, 뮤텍스는 동기화 대상이 오로지 하나일 때 사용된다.
- 점유와 대기(Hold and Wait)
최소한 하나의 자원을 점유하고 있으면서 다른 프로세스에 할당되어 사용하고 있는 자원을 추가로 점유하기 위해 대기하는 프로세스가 있어야 한다.
- 비선점(Non-preemption)
다른 프로세스에 할당된 자원은 사용이 끝날 때까지 강제로 빼앗을 수 없어야 한다.
- 환형 대기(Circular Wait)
서로 다른 공유자원을 사용하기 위해 대기하는 프로세스들이 원형으로 구성되어 있어 자신에게 할당된 자원을 점유하면서 앞이나 뒤에 있는 프로세스의 자원을 요구한다.
교착 상태 해결 방안
- 예방(Prevention)
교착상태가 발생하지 않도록 사전에 시스템을 제어하는 방법으로, 교착상태 발생의 4가지 조건 중에서 어느 하나를 제거한다. 즉, 자원 낭비가 가장 심한 해결 방법이다.
- 상호 배제 부정 : 한 번에 여러 개의 프로세스가 공유 자원을 사용할 수 있도록 한다.
- 점유 및 대기 부정 : 프로세스가 실행되기 전 필요한 모든 자원을 할당하여 프로세스 대기를 없애거나 자원이 점유되지 않은 상태에서만 자원을 요구한다.
- 비선점 부정 : 자원을 점유하고 있는 프로세스가 다른 자원을 요구할 때 점유하고 있는 자원을 반납하고, 요구한 자원을 사용하기 위해 기다린다.
- 환형대기 부정 : 자원을 선형 순서로 분류하여 고유 번호를 할당하고, 각 프로세스는 현재 점유한 자원의 고유 번호보다 앞이나 뒤 어느 한쪽 방향으로만 자원을 요구하도록 한다.
- 회피(Avoidance)
교착상태가 발생할 가능성을 배제하지 않고 교착상태가 발생하면 적절히 피해나가는 방법으로, 주로 은행원 알고리즘(Banker’s Algorithm)이 사용된다.
은행원 알고리즘
- 은행원 알고리즘은 다익스트라가 제안한 기법으로, 은행에서 모든 고객의 요구가 충족되도록 현금을 할당하는데서 유래한 기법이다.
- 각 프로세스에게 자원을 할당하여 교착상태가 발생하지 않으면 모든 프로세스가 완료될 수 있는 상태를 안전상태, 교착상태가 발생할 수 있는 상태를 불안전 상태라고 한다.
- 은행은 자원을 할당한 후에도 안정 상태로 남아있는지 검사하여 안정 상태에 있으면 자원을 할당하고 그렇지 않으면 다른 프로세스들이 자원을 해제할 때까지 대기한다.
- 은행원 알고리즘을 적용하기 위해서는 자원의 양과 사용자(프로세스) 수가 일정해야 한다.
- 은행원 알고리즘은 프로세스의 모든 요구를 유햔한 시간안에 할당하는 것을 보장한다.
- 탐지(Detection)
시스템에 교착상태가 발생했는지 점검하여 교착상태에 있는 프로세스와 자원을 발견한다.
교착 상태 발견 알고리즘과 자원 할당 그래프등을 사용할 수 있다.
- 복구(Recovery)
교착상태를 일으킨 프로세스를 종료하거나 교착상태의 프로세스에 할당된 자원을 선점하여 프로세스나 자원을 회복한다.
프로세스 종료
- 교착상태에 있는 프로세스를 종료
- 교착상태에 있는 프로세스들을 하나씩 종료
자원 선점
- 교착상태의 프로세스가 점유하고 있는 자원을 선점하여 다른 프로세스에게 할당하며, 해당 프로세스를 일시 정지시키는 방법이다. 우선순위가 낮은 프로세스, 수행된 정도가 적은 프로세스, 사용되는 자원이 적은 프로세스등을 위주로 해당 프로세스의 자원을 선점한다.