꾸준히
동기화 본문
동기화란
어떤 작업이 크리티컬 섹션이라고 판단되었을 경우, 해당 크리티컬 섹션을 아토믹 오퍼레이션으로 만들어 주는 것입니다
어떤 작업이 아토믹하다는 것을 쉽게 표현하면 해당 작업이 끝날 때까지 컨텍스트 스위칭이 발생하지 않는다는 것을 의미합니다
즉, 해당 작업을 원자처럼 더 이상 쪼갤 수 없다는 의미를 살리기 위해 아토믹이라는 이름이 붙은 것입니다
어떤 작업이 아토믹하게 구현되어야만 한다면 해당 작업을 크리티컬 섹션이라고 부릅니다
크리티컬 섹션을 만들려면 여러 태스크 혹은 여러 코어가 공유하는 공유 자원이 있어야 합니다
동기화를 구현하는 알고리즘에는 여러 종류가 있습니다
첫 번째는 가장 많이 쓰는 세마포어, 두 번째는 뮤텍스, 세 번째는 스핀락입니다
세마포어
sem_init 함수에서 세마포어의 개수를 설정합니다 이 세마포어의 개수에 따라서 크리티컬 섹션에 진입할 수 있는 태스크들의 수가 증가합니다
sem_test 함수는 세마포어를 획득 할 수 있는지 (크리티컬 섹션에 진입이 가능한지) 확인하고 획득할 수 있다면 남은 세마포어 개수에서 하나를 뺍니다 (세마포어를 잠금) 획득 할 수 없다면 false를 반환 합니다
여기서 동기화를 구현하는 두 가지 중요한 개념이 나옵니다 바로 잠금과 잠금의 해제입니다
크리티컬 섹션에 들어갈 때 잠그고 크리티컬 섹션을 나올 때 자금을 푸는 것입니다
잠겨 있는 도중에는 컨텍스트 스위칭도 발생하지 않고 다른 코어가 끼어들지도 못하며 다른 태스크들이 크리티컬 섹션에 진입하지 못하게 됩니다
뮤텍스
세마포어는 잠금에 대한 소유 개념이 없으므로 누가 잠근 세마포어이든 간에 누구나 잠금을 풀 수 있습니다 그러나 뮤텍스는 소유의 개념이 있습니다 소유의 개념이 있다는 것은 뮤텍스를 잠근 태스크만이 뮤텍스의 잠금을 풀 수 있다는 말입니다
다시 말해 뮤텍스는 바이너리 세마포어에 소유의 개념을 더한 동기화 알고리즘이라고 볼 수 있습니다
바이너리 세마포어란 세마포어의 전체 개수가 1개인 세마포어를 말합니다
코드를 보면 owner의 값과 뮤텍스 전역 변수에 저장되어 있는 owner의 값을 비교하는 코드가 있습니다 이 비교 코드를 통과해야 뮤텍스의 잠금을 풀 수 있습니다 소유자를 확인하고 뮤텍스를 잠갔던 소유자일 때만 뮤텍스의 잠금 해제를 허용하는 것입니다
스핀락
스핀락은 바쁜 대기 개념의 크리티컬 섹션 보호 기능입니다 바쁜 대기란 스케줄링을 하지 않고 CPU를 점유한 상태, 즉 CPU가 여전히 바쁜 상태에서 락이 풀리는 것을 대기한다는 말입니다
스케줄링을 하지 않고 짧은 시간 동안 CPU를 정유하면서 잠금이 풀리는 것을 기다린다는 아이디어이므로 멀티코어 환경에서 유용하게 쓰이기도 합니다 하지만 싱글코어 환경에서는 다른 태스크가 잠금을 풀려면 어차피 스케줄링을 해야 하므로 스핀락의 개념을 사용할 수가 없습니다
실제 스핀락은 바쁜 대기 자체가 완전히 아토믹해야 하기 때문에 배타적 메모리 연산을 지원하는 어셈블리어 명령으로 구현됩니다 아래 코드는 C언어 코드로 의사 코드입니다 (개념 이해 용도)
아래 코드를 이해할 때는 해당 하무가 아토믹하게 동작한다고 생각해야 합니다
static bool sSpinLock = false;
void spin_lock(void)
{
while(sSpinLock); // wait
sSpinLock = true; // lock
}
void spin_unlock(void)
{
sSpinLock = false; // unlock
}