동기화
한정적인 시스템 자원에 여러 스레드가 동시에 접근해서 사용하면 문제가 발생할 수 있음. 이 문제를 방지하기 위해 여러 스레드에게 하나의 자원에 대한 처리 권한을 주거나 순서를 조정하는 기법.
스레드 동기화
- 실행 순서의 동기화 : 스레드의 실행 순서를 정의하고, 이 순서를 반드시 따르도록 하는 것.
- 메모리 접근에 대한 동기화
- 메모리 접근에 있어서 동시 접근을 막는 것.
- 실행의 순서가 중요한 것이 아니라 한 순간에 하나의 스레드만 해당 자원에 접근하도록 하는 것.
Windows 동기화 기법
- 유저 모드의 동기화(User Mode Synchronize)
- 커널의 힘을 빌리지 않는 동기화 기법(커널의 코드가 실행되지 않음)
- 성능상 이점이 있으나 기능상의 제한점이 존재.
- 임계 구역 기반의 동기화, 인터락 함수 기반의 동기화.
- 커널 모드 동기화(Kernel Mode Synchronize)
- 커널에서 제고하는 동기화 기능을 활용하는 방법.
- 따라서 동기화 관련된 함수가 호출될 때 마다 커널 모드로의 변경이 필요하고, 이는 성능의 저하로 이어지게 됨.
- 하지만 그만큼 유저 모드 동기화에서 제공하지 못하는 기능을 제공 받을 수 있다. ( ex. 세마포어, 뮤텍스, 모니터 등등 . )
하드웨어, HAL, 마이크로 커널, 각종 관리자 => 커널 모드
응용 프로그램 => 유저 모드
아래에서는 '메모리 접근의 동기화'에 대해 알아볼 것이다.
메모리 영역의 접근을 동기화 한다는 것은 '임계 영역의 접근을 동기화'하겠다는 뜻이다.
임계 영역이란 ?
- 둘 이상의 스레드가 동시에 접근해서는 안되는 공유 자원을 접근하는 코드의 일부를 말함.
- 임계 영역에서 동기화를 진행하지 못하면 치명적인 문제가 발생.
- 따라서 임계 구역 문제를 해결하기 위해서는 3가지 필수 조건이 있다.
i. 상호 배제(Mutual exclusion) : 프로세스 P1이 공유 자원을 접근하는 임계 구역 코드를 수행하고 있으면 다른 프로세스들은 공유 자원을 접근하는 임계구역 코드를 수행할 수 없다. 즉, 한 순간에 하나의 스레드만이 실행 될 수 있다.
ii. 진행(Progress) : 임계 구역에서 실행중인 프로세스가 없고 별도의 동작이 없는 프로세스들만 임계 구역 진입 후보로서 참여될 수 있다.
iii. 한정된 대기(Bounded Waiting) : P1이 임계 구역에 진입 신청 후부터 받아들여질때까지, 다른 프로세스들이 임계 구역에 진입하는 횟수는 제한이 있어야 한다.
유저모드의 동기화
- 임계 구역 기반의 동기화
- 열쇠를 얻은 프로세스만 임계 구역에 들어갈 수 있다. 즉, 한번에 하나의 스레드만이 접근 가능
- 임계 구역 진입을 위해 크리티컬 섹션 오브젝트를 얻는다.
- 다른 스레드가 열쇠를 가지고 있을 시에는 반환할 때 까지 블로킹된다. 열쇠가 반환되면 블로킹 상태에 빠져나와 열쇠를 얻고 임게 구역에 접근함.
- 인터락 함수 기반의 동기화
- 함수 내부적으로 한 순간에 하나의 스레드에 의해서만 실행되도록 동기화.
- 임계 구역 기반의 동기화도 내부적으로 인터락 함수를 기반으로 구현.
- 유저 모드 기반으로 동작해서 속도가 빠름.
커널모드의 동기화
- 세마포어(SemaPhore)
-
공유된 자원의 데이터를 여러 프로세스, 스레드가 접근하는 것을 막는 것.
-
동시에 접근할 수 있는 '허용 가능한 갯수'를 가지고 있는 Counter. (공유자원에 접근할 수 있는 스레드 혹은 프로세스의 수를 나타내는 값. -> 공통으로 관리하는 하나의 값)
-
Ex)
화장실을 예로 들면, 세마포어는 1개 이상의 열쇠라고 할 수 있다.
화장실 칸이 4개이고 열쇠가 4개라면, 4명까지는 대기없이 바로 사용할 수 있다. 그 다음부터는 대기를 해야 한다. 이것이 바로 세마포어이다.
-
세마포어 Counter의 갯수에 따라 다음과 같이 나뉜다.
- 1개 : Binary Semaphore(뮤텍스와 같다.)
- 2개 이상: Counting Semaphore
-
세마포어는 소유할 수 없다.
- 세마포어를 소유하지 않는 스레드가 세마포어를 해제할 수 있는 문제가 발생.
- 뮤텍스(Mutal Exclusion)
- 공유된 자원의 데이터를 여러 프로세스, 스레드가 접근하는 것을 막는 것이다.
- 임계 구역을 가진 스레드들의 Running time이 서로 겹치지 않게 각각 단독으로 실행되게 하는 기술.
- 뮤텍스 객체를 두 스레드가 동시에 사용할 수 없다.
- 일종의 Locking 매커니즘으로 공유 자원에 대한 접근을 조율하기 위해 locking과 unlocking을 사용.
- Lock에 대한 소유권이 있으며 Lock을 가지고 있을 경우에만 공유 자원에 접근 할 수 있고, Lock을 가진 사람만 반납할 수 있다.
- 뮤텍스는 무조건 1개의 열쇠만 가질 수 있다. 열쇠를 가진 사람만이 화장실에 갈 수 있고, 다음 사람이 화장실에 가기 위해서는 앞 사람이 열쇠를 반납해야 한다.
- 모니터(Monitor)
- Mutex(LocK)와 Condition Variables를 가지고 있는 Synchronization 매커니즘이다.
뮤텍스와 모니터는 상호 배제를 함으로써 임게 구역에 하나의 쓰레드만 들어갈 수 있다.
반면, 세마포어는 하나의 쓰레드만 들어가거나 혹은 여러개의 쓰레드가 들어가게 할 수도 있다.
뮤텍스와 모니터의 차이는?
- 뮤텍스는 다른 프로세스나 스레드 간에 동기화를 위해 사용.
- 모니터는 하나의 프로세스내에서 다른 스레드 간에 동기화할 때 사용.
- 뮤텍스는 운영체제 커널에 의해 제공됨.(무겁고 느림)
- 모니터는 프레임워크나 라이브러리 그 자체에서 제공됨. ( 가볍고 빠름)
세마포어와 모니터의 차이는?
- 자바에서는 모니터를 모든 객체에게 기본적으로 제공하지만 C에서는 사용할 수 없음.
- 세마포어는 카운터라는 변수값으로 프로그래머가 상호 배제나 정렬의 목적으로 사용시 매번 값을 따로 지정해줘야 하는 등 조금 번거롭다.
- 반면, 모니터는 이러한 일들이 캡슐화되어 있어서 개발자는 카운터 값을 0 또는 1으로 주어야 하는 고민을 할 필요가 없이 synchronized, wait(), notify() 등의 키워드를 이용해 좀 더 편하게 동기화할 수 있다.
세마포어와 뮤텍스의 차이는?
- 세마포어는 뮤텍스가 될 수 있지만, 뮤텍스는 세마포어가 될 수 없다.
- 세마포어는 소유할 수 없으며 , 뮤텍스는 소유할 수 있고 소유주가 그 책임을 진다.
- 뮤텍스의 경우 뮤텍스를 소유하고 있는 스레드가 이 뮤텍스를 해제할 수 있다. 하지만 세마포어는 소유하지 않고 있는 다른 스레드가 세마포어를 해제할 수 있다.
- 뮤텍스는 동기화 대상이 1개일 때 사용하고 세마포어는 동기화 대상이 여러 개 일때 사용한다.
뮤텍스, 세마포어 예시
뮤텍스
뮤텍스는 화장실이 하나뿐인 식당과 비슷하다. 화장실에 가기 위해서 카운터에서 열쇠를 받아가야 한다.
내가 화장실을 가려고 하는데 카운터에 키가 있으면 화장실에 사람이 없다는 의미이고 나는 열쇠를 가지고 화장실에 갈 수 있다.
화장실에 가고 싶은 다른 사람이 있다. 이 사람은 급하지만 열쇠가 없기 때문에 화장실에 갈 수 없고 기다려야 한다. 내가 용무를 끝내 나올 때까지 카운터에서 기다려야 한다. 또 다른 사람도 화장실에 가고 싶어 카운터에서 대기한다.
나는 화장실에 나와 카운터를 키를 올려 놓는다. 이제 기다리던 사람들 중 맨 앞에 있던 사람은 키를 받을 수 있고 화장실에 갈 수 있다.
이게 뮤텍스가 동작하는 방식이다.
화장실을 이용하는 사람 : 프로세스 혹은 스레드
화장실: 공유 자원
화장실 키 : 공유 자원에 접근하기 위해 필요한 어떤 오브젝트.
즉, 뮤텍스는 Key에 해당하는 어떤 오브젝트가 있으며 이 오브젝트를 소유한 프로세스나 스레드만이 공유 자원에 접근할 수 있다.
세마포어
화장실을 좀 더 쉽게 이용할 수 있는 레스토랑으로 생각하면 된다. 레스토랑의 화장실은 여러 개의 칸이 있다. 그리고 화장실 입구에는 현재 화장실의 빈칸 갯수를 보여주는 전광판이 있다.
나는 화장실에 가고 싶고, 입구에서 빈 칸의 갯수를 확인하고 1개 이상이라면 빈칸의 갯수를 하나 뺀 다음 화장실에 입장해야 한다. 그리고 나올 때, 빈칸의 갯수를 복구하기 위해 하나를 더해준다.
모든 칸에 사람이 들어갔을 경우, 빈칸의 갯수는 0이 되며 이때 화장실에 들어가고자 하는 사람이 있다면 빈칸의 갯수가 1로 바뀔때까지 기다려야 한다.
이용을 마친 사람들은 나오면서 빈칸의 갯수를 1씩 더한다. 그리고 기다리던 사람은 이 숫자에서 다시 1을 뺀 다음 화장실로 입장한다.
세마포어는 공통으로 관리하는 하나의 값을 이용해 상호배제를 달성한다.
화장실을 이용하는 사람 : 프레소스 혹은 스레드
화장실 : 공유 자원
화장실 빈칸의 갯수 : 현재 공유 자원에 접근할 수 있는 스레드, 프로세스의 갯수를 나타냄.
뮤텍스 : 한 스레드, 프로세스에 의해 소유될 수 있는 Key를 기반으로 한 상호배제 기법
세마포어 : 현재 공유자원에 접근할 수 있는 스레드, 프로세스의 수를 나타내는 값을 두어 상호배제를 달성하는 기법
뮤텍스와 세마포어의 목적은 특정 동기화 대상이 이미 특정 스레드나 프로세스에 의해 사용중일 경우, 다른 스레드가 해당 동기화 대상에 접근하는 것을 제한하는 것으로 동일하지만, 관리하는 동기화 대상이 몇개인가에 따라 차이가 생긴다.
참고자료