Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

꾸준히

동기화 본문

RTOS

동기화

S210530 2022. 10. 22. 19:42

동기화란

어떤 작업이 크리티컬 섹션이라고 판단되었을 경우, 해당 크리티컬 섹션을 아토믹 오퍼레이션으로 만들어 주는 것입니다
어떤 작업이 아토믹하다는 것을 쉽게 표현하면 해당 작업이 끝날 때까지 컨텍스트 스위칭이 발생하지 않는다는 것을 의미합니다
즉, 해당 작업을 원자처럼 더 이상 쪼갤 수 없다는 의미를 살리기 위해 아토믹이라는 이름이 붙은 것입니다
어떤 작업이 아토믹하게 구현되어야만 한다면 해당 작업을 크리티컬 섹션이라고 부릅니다
크리티컬 섹션을 만들려면 여러 태스크 혹은 여러 코어가 공유하는 공유 자원이 있어야 합니다
동기화를 구현하는 알고리즘에는 여러 종류가 있습니다
첫 번째는 가장 많이 쓰는 세마포어, 두 번째는 뮤텍스, 세 번째는 스핀락입니다

 

세마포어

void Kernel_sem_init(int32_t max)
{
    sSemMax = (max <= 0) ? DEF_SEM_MAX : max;
    sSemMax = (max >= DEF_SEM_MAX) ? DEF_SEM_MAX : max;

    sSem = sSemMax;
}

bool Kernel_sem_test(void)
{
    if (sSem <= 0)
    {
        return false;
    }

    sSem--;

    return true;
}

void Kernel_sem_release(void)
{
    sSem++;

    if (sSem >= sSemMax)
    {
        sSem = sSemMax;
    }
}

sem_init 함수에서 세마포어의 개수를 설정합니다 이 세마포어의 개수에 따라서 크리티컬 섹션에 진입할 수 있는 태스크들의 수가 증가합니다
sem_test 함수는  세마포어를 획득 할 수 있는지 (크리티컬 섹션에 진입이 가능한지) 확인하고 획득할 수 있다면 남은 세마포어 개수에서 하나를 뺍니다 (세마포어를 잠금) 획득 할 수 없다면 false를 반환 합니다
여기서 동기화를 구현하는 두 가지 중요한 개념이 나옵니다 바로 잠금과 잠금의 해제입니다
크리티컬 섹션에 들어갈 때 잠그고 크리티컬 섹션을 나올 때 자금을 푸는 것입니다
잠겨 있는 도중에는 컨텍스트 스위칭도 발생하지 않고 다른 코어가 끼어들지도 못하며 다른 태스크들이 크리티컬 섹션에 진입하지 못하게 됩니다

 

뮤텍스

세마포어는 잠금에 대한 소유 개념이 없으므로 누가 잠근 세마포어이든 간에 누구나 잠금을 풀 수 있습니다 그러나 뮤텍스는 소유의 개념이 있습니다 소유의 개념이 있다는 것은 뮤텍스를 잠근 태스크만이 뮤텍스의 잠금을 풀 수 있다는 말입니다
다시 말해 뮤텍스는 바이너리 세마포어에 소유의 개념을 더한 동기화 알고리즘이라고 볼 수 있습니다
바이너리 세마포어란 세마포어의 전체 개수가 1개인 세마포어를 말합니다

typedef struct KernelMutext_t
{
    uint32_t owner;
    bool     lock;
} KernelMutext_t;
 
KernelMutext_t sMutex;
 
void Kernel_mutex_init(void)
{
    sMutex.owner = 0;
    sMutex.lock = false;
}

bool Kernel_mutex_lock(uint32_t owner)
{
    if (sMutex.lock)
    {
        return false;
    }

    sMutex.owner = owner;
    sMutex.lock = true;
    return true;
}

bool Kernel_mutex_unlock(uint32_t owner)
{
    if (owner == sMutex.owner)
    {
        sMutex.lock = false;
        return true;
    }
    return false;
}

코드를 보면 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
}

 

'RTOS' 카테고리의 다른 글

Context Switching  (0) 2023.05.29
이벤트와 메시징  (0) 2022.10.22
Task  (0) 2022.10.22
인터럽트  (0) 2022.10.22
HAL  (0) 2022.10.22