공유된 자원 속 하나의 데이터는 한 번에 하나의 프로세스만 접근할 수 있도록 제한해 두어야 하는데, 공유된 자원에 여러 개의 프로세스가 동시에 접근하면 문제가 발생합니다.
이를 해결하기 위해 데이터에 접근을 한 번에 하나의 프로세스만 할 수 있도록 제한을 두는 "동기화 방식" 을 취해야 합니다.
이 둘을 살펴보기 이전에 "임계 영역" 과 "스핀락" 이라는 용어를 살펴보고 가겠습니다.
둘 이상의 스레드가 공유 자원에 접근할 때, 오직 한 스레드만의 접근을 허용해야 하는 경우에 사용합니다.
여러 프로세스가 데이터를 공유하며 수행될 때,
각 프로세스에서 공유 데이터를 접근하는 프로그램 코드 블록입니다.
즉, 여러 프로세스가 동일 자원을 동시에 참조하여 값(공유하는 변수명, 파일 등)이 오염될 위험 가능성이 있는 영역
프로그래밍 시, 성능 향상을 위해 임계영역을 최소화하는 설계를 해야 합니다.
임계영역이 락이 걸려서 진입이 불가능할 때, 임계영역이 언락되어 진입이 가능해질 때까지 루프를 돌면서 무작정 반복으로 재시도하며 스레드가 CPU를 점유하고 있는 상태를 말합니다.
이때, CPU를 점유하여 무의미한 코드를 계속 수행하면서 임계영역이 언락되길 기다리는 것이기 때문에 스핀락은 Busy Waiting 상태입니다.
스핀락은 운영체제의 스케줄링 지원을 받지 않기 때문에, 해당 스레드에 대한 문맥 교환(context switch)이 일어나지 않습니다.
임계영역이 짧은 시간 안에 언락되어 진입이 가능한 상태이면 context switch 비용이 들지 않아 효율적일 수 있지만,
임계영역이 오랜 시간동안 언락되지 않으면 그 시간동안 계속 CPU를 점유하고 있어 다른 스레드가 사용하지 못하기 때문에 오버헤드도 존재합니다.
스핀락은 상태가 오직 획득(Lock) / 해제(Unlock)만 존재하기에 한 번에 하나의 컴포넌트만 접근이 가능하며, 획득과 해제의 주체는 동일해야 합니다.
스핀락은 context switch가 일어나지 않기 때문에 멀티 프로세서 시스템에서만 사용 가능합니다.
뮤텍스(Mutex)는 상호 배제(Mutual Exclusion)의 약자입니다.
뮤텍스는 상태가 오직 획득(Lock) / 해제(Unlock)만 존재한다는 점은 스핀락과 동일합니다.
lock: 현재의 임계 구역에 들어갈 권한을 얻어온다. 만일 다른 프로세스/스레드가 임계 구역을 수행 중이라면 종료할때까지 대기한다(entry section).
unlock: 현재의 임계 구역을 모두 사용했음을 알린다. 대기중인 다른 프로세스/스레드가 임계 구역에 진입할 수 있다(exit section).
스핀락과 뮤택스와 달리 표현형이 정수형이다. 이 점을 살려 하나 이상의 컴포넌트가 공유자원에 접근할 수 있도록 허용할 수 있습니다.
컴포넌트가 특정 자원에 접근할 때 semWait이 먼저 호출되어 임계영역에 들어갈 수 있는지 먼저 확인합니다.
임계영역에 접근이 가능하다면 semWait을 빠져나와 임계영역에 들어가고, 이후 semSignal이 호출되어 임계영역에서 빠져나옵니다.
semWait 연산:
세마포어의 값을 감소. 만약 값이 음수가 되면 semWait을 호출한 스레드는 블록되지만 음수가 아니면 작업을 수행한다.semSignal 연산:
세마포어의 값을 증가. 만약 값이 양수가 아니라면 semWait 연산에 의해 블록된 스레드를 다시 wake시킨다.
세마포어의 값은 자원의 수를 의미하고, 세마포어는 사용할 수 있는 자원의 개수에 따라 두가지 유형이 있습니다.
Counting Semaphore(개수 세마포어):
도메인이 0 이상인 임의의 정수값인 세마포어이다.
여러개의 자원을 가질 수 있으며, 제한된 자원을 가지고 액세스 작업할 때 사용한다.Binary Semaphore (이진 세마포어)
0 또는 1 값만 가질 수 있는 세마포어이다.
임계영역 문제를 해결하는 데에 사용하며, 자원이 하나이기 때문에 뮤텍스로도 사용할 수 있다.