임베디드

[Thread] 멀티스레드와 임계영역의 mutex init/lock/unlock/destory

히똔 2022. 4. 22. 16:09
728x90
반응형

멀티스레드를 사용하다보면 데이터가 공유되기 때문에 의도한 대로 데이터가 변경되지 않을 수 있다.
그럴 때 mutex lock 을 이용하여 임계영역을 설정하고 데이터를 보호할 수 있다.

 

임계영역 (Critical Section)

스레드나 프로세스가 동시에 접근해서는 안되는 곳으로, mutex_lock으로 보호해주어야한다.

 

멀티스레드 버그가 발생하는 이유


개발자의 의도는 40000 이 출력되도록 만드는 것이다. 그런데 실제로 실행해보면 아니다.

순서는 보장이 안되는 걸 아니까 누가 먼저 실행될지는 모르지만 어쨌든 10000을 네번 도니까 40000이 나올것이라고 예상할 것이다.
그런데 40000은 안나오고 매번 그 이하의 숫자가 나온다.

 

이런 일이 발생하는 이유는 스레드와 메모리 사이의 데이터 이동 순서가 순차적이지 않기 때문이다.

예를 들어 메모리에서 cnt++를 하여 cnt값이 6이 되었다고 하자.
그러면 첫번째 스레드에 들어가서 6이 저장된 다음 또 다시 cnt++ 가 되어 두번째 스레드에 들어가 7이 될 것이라는 게 기본적으로 생각하는 실행 순서이다.

하지만, 첫번째 스레드가 메모리에 값을 전달하기도 전에, 두번째 스레드가 메모리속 cnt 값을 먼저 가져가버린다. 그래서 아직 6으로 바뀌지도 않았는데 두번째 스레드가 cnt 값을 가져간다. 그렇기 때문에 첫번째 스레드 내 cnt++가 무시될 수 있다. 결국 40000에 도달할 수 없는 것이다.

이렇듯 스레드의 실행순서를 예측할 수 없기 때문에 이런일이 발생한다.

 

Thread Syncronization (스레드 동기화)


임계영역을 동시에 수행하지 않도록 하기 위해 스레드간 협의를 맞추는 것이다
둘이서 하나의 자원을 쓸때 한명씩 돌아가면서 쓰기 위해서 협의를 봐야한다.

동기화 알고리즘은 pthread가 지원하고 그 중 mutex_lock에 대해 알아보자

 

Mutex_lock


mutex_lock 객체를 이용하여 한 스레드가 임계영역을 사용하고 있을 때 다른 스레드가 사용하지 못하도록 잠구는 것이다.

쉽게 화장실 키라고 생각하면 된다.
손님이 식당에서 화장실을 가고 싶어하면 주인이 키를 준다.
그러면 다른 사람들은 해당 손님이 화장실 키를 주인에게 되돌려 줄때까지는 화장실 사용이 제한된다. 

mutex lock 을 화장실 키에 비유

 

1. Mutex lock 변수 선언

pthread_mutex_t mlock;

 

2. 객체 초기화

pthread_mutex_init(&mlock, attr);

mutex 를 초기화하여 mutex 를 실행할 준비를 해준다.

 

3. Mutex lock 얻기 ( = 화장실 키 요청 )

pthread_mutex_lock(&mlock);

임계 영역 상단에 락을 걸어준다

 

4. Mutex unlock ( = 화장실 키 돌려주기 )

pthread_mutex_unlock(&mlock);

임계 영역이 끝나면 락을 풀어준다.

 

5. 객체 제거

pthread_mutex_destroy(&mlock);

 Mutex 객체를 제거하여 메모리 효율성을 높인다.

 

Mutex lock 예시 코드


#include <stdio.h>
#include <pthread.h>

pthread_mutex_t mlock;
pthread_t tid[4];
int cnt;

void *run(){
    pthread_mutex_lock(&mlock);
    for(int i=0;i<10000;i++) cnt++;
    pthread_mutex_unlock(&mlock);
}

int main(){
    pthread_mutex_init(&mlock, NULL);

    for(int i=0;i<4;i++){
        pthread_create(&tid[i], NULL,run, NULL);
    }
    for(int i=0;i<4;i++) pthread_join(tid[i],NULL);

    pthread_mutex_destroy(&mlock);
    printf("%d\n",cnt);

    return 0;
}

mutex lock에 필요한 함수들을 중간중간 추가해주면 40000이 제대로 잘 나온다.

 


멀티스레드 자체도 겁나 어려운데 뮤텍스까지 할려니까 진짜 뇌 과부화 올 뻔했다 ㅋㅋㅋ
그래도 이렇게 블로그에 정리하니까 훨씬 나아졌다..

멀티스레드 & 뮤텍스를 확실히 잡고가기 위해서 미니게임도 하나 만들었는데 이것도 조만간 정리해서 올리겠다!!

 

728x90
반응형