본문 바로가기
IT/c, c++

pthread 에서 mutex 사용법 #Feat. pthread_mutex_lock, pthread_mutex_unlock

by TechTonic 2022. 12. 14.
반응형

여러 쓰레드에서 공유자원(변수 등..)이 사용될 경우 원치 않게 공유 자원 값이 변경되는 일이 발생된다.

이를 방지하기 위해 진입한 순서에 따라 값이 사용되도록 하기 위해 mutex 가 사용된다.

 

mutex 사용 시 아래 중요 api에 대해 알아보자.

#include <pthread.h>

int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);

 

각 api 에 대해 알아보자.

 

pthread_mutex_lock, pthread_mutex_unlock

  • lock 은 공유자원을 사용하는 시점에 해당 코드에 lock을 걸어 다른 쓰레드에서 해당 코드에 진입을 못하도록 막는 역할을 합니다. 반대로 unlock는 선 진입한 쓰레드가 작업이 끝나면 unlock를 실행하여 다른 쓰레드에서 해당 코드를 실행 할 수 있도록 lock를 풀어주는 역할을 합니다. 상세한 내용은 아래 샘플 코드를 통해 확인 할 수 있으니 느낌만 가지고 있으면 됩니다.

pthread_mutex_destroy

  • mutex 객체를 삭제하고 자원을 되돌려 줍니다.

 

아래는 mutex가 사용되는 예시 입니다.

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <Windows.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int cnt=0;

void *threadCount(void *arg)
{
    int i;
    char* name = (char*)arg;

    cnt = 0;
    for (i = 0; i <10; i++)
    {
        printf("%s cnt: %d\n", name,cnt);
        Sleep(50);
        cnt++;
        
    }
}


int main()
{
    pthread_t thread1;
    pthread_t thread2;

    pthread_create(&thread1, NULL, threadCount, (void *)"thread1");
    pthread_create(&thread2, NULL, threadCount, (void *)"thread2");

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

}

 

위 코드 실행 시 예측되는 값은 thread1, thread2 가 각각 threadCount 함수에 진입하여 thread 각각 cnt 를 0부터 9까지 로그찍는걸 예상 할 수 있습니다.

하지만 결과는 아래와 같이 원하는 값이 출력되지 않습니다.

thread1 cnt: 0
thread2 cnt: 0
thread1 cnt: 1
thread2 cnt: 2
thread1 cnt: 3
thread2 cnt: 4
thread1 cnt: 5
thread2 cnt: 6
thread1 cnt: 7
thread2 cnt: 8
thread1 cnt: 9
thread2 cnt: 10
thread1 cnt: 11
thread2 cnt: 12
thread1 cnt: 13
thread2 cnt: 14
thread1 cnt: 15
thread2 cnt: 16
thread1 cnt: 17
thread2 cnt: 18

이유는 cnt 변수 값을 공유자원으로 사용하고 있기 때문입니다.

그럼 각 thread 가 각각 cnt 값을 0~9 까지 출력하려면 어떻게 해야할까요? 이때 mutex 가 필요합니다.

 

아래는 mutex를 사용한 코드 입니다.

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <Windows.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int cnt=0;

void *threadCount(void *arg)
{
    int i;
    char* name = (char*)arg;

    printf("pthread_mutex_lock Ready %s\n",name);
    pthread_mutex_lock(&mutex);
    printf("pthread_mutex_lock Start %s\n",name);

    cnt = 0;
    for (i = 0; i <10; i++)
    {
        printf("%s cnt: %d\n", name,cnt);
        Sleep(50);
        cnt++;
        
    }

    printf("pthread_mutex_unlock Ready %s\n",name);
    pthread_mutex_unlock(&mutex);
    printf("pthread_mutex_unlock Start %s\n",name);
}


int main()
{
    pthread_t thread1;
    pthread_t thread2;

    pthread_create(&thread1, NULL, threadCount, (void *)"thread1");
    pthread_create(&thread2, NULL, threadCount, (void *)"thread2");

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    pthread_mutex_destroy(&mutex);
}

 

해당 코드로 실행된 로그를 보면 실행된 절차 확인이 가능합니다.

pthread_mutex_lock Ready thread1
pthread_mutex_lock Start thread1
thread1 cnt: 0
pthread_mutex_lock Ready thread2
thread1 cnt: 1
thread1 cnt: 2
thread1 cnt: 3
thread1 cnt: 4
thread1 cnt: 5
thread1 cnt: 6
thread1 cnt: 7
thread1 cnt: 8
thread1 cnt: 9
pthread_mutex_unlock Ready thread1
pthread_mutex_unlock Start thread1
pthread_mutex_lock Start thread2
thread2 cnt: 0
thread2 cnt: 1
thread2 cnt: 2
thread2 cnt: 3
thread2 cnt: 4
thread2 cnt: 5
thread2 cnt: 6
thread2 cnt: 7
thread2 cnt: 8
thread2 cnt: 9
pthread_mutex_unlock Ready thread2
pthread_mutex_unlock Start thread2

첫번째 출력된 로그를 보면 thread 1이 threadCount 함수에 진입하여 pthread_mutex_lock() 을 걸어둡니다.

이후 cnt 를 출력하며, 이때 thread 2가 threadCount 함수에 진입합니다.

thread 2 도 진입후 lock 을 걸려고 하지만 이미 thread 1에서 lock을 걸어둔 상태이기 때문에 해당 코드에서 잠시 멈춤상태가 됩니다.

thread 1은 for문 작업이 끝난 후 unlock 을 실행하며, unlock 이 실행된 시점에 thread 2는 해당 코드에 진입할 수 있습니다.

 

반응형

댓글