여러 쓰레드에서 공유자원(변수 등..)이 사용될 경우 원치 않게 공유 자원 값이 변경되는 일이 발생된다.
이를 방지하기 위해 진입한 순서에 따라 값이 사용되도록 하기 위해 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는 해당 코드에 진입할 수 있습니다.
'IT > c, c++' 카테고리의 다른 글
특정 폴더 모니터링 inotify_add_watch 사용법 (0) | 2023.06.29 |
---|---|
VSCode 에서 pthread 사용하는 방법 (26) | 2022.12.09 |
Visual Studio Code C/C++ 환경 구축 #Feat. VScode (12) | 2022.12.09 |
댓글