조건 변수를 사용하는 이유
이전 글(https://shyeon.tistory.com/48)에서 mutex를 이용하여 스레드간 동기화를 하는 방법을 알아 보았다. 하지만 mutex만을 이용하여 동기화를 하는 것은 프로세스가 mutex변수를 지속적으로 검사해야 한다는 단점이 있다. 따라서 이 글에서 다루는 조건 변수(condition)을 함께 사용한다.
함수
함수는 mutex함수와 굉장히 유사하다.
1. pthread_cond_init
int pthread_cond_init(pthread_cond_t *restrict condition, pthread_condattr_t *restrict attr);
mutex변수를 초기화하는 것처럼 cond변수도 초기화를 해야한다. 첫 번째 인자는 초기화하려는 cond 변수의 주소값을 넘기고 두 번째 인자는 cond 변수의 속성을 설정하는 변수이고 리눅스에선 무시하므로 NULL값을 주로 넣는다.
mutex 변수처럼 pthread_cond_init함수 말고 직점 변수에 PTHREAD_COND_INITIALIZER를 대입하여 초기화하는 방법도 있다.
2. pthread_cond_destroy
int pthread_cond_destroy(pthread_cond_t *condition);
mutex 변수와 마찬가지로 사용이 끝난 cond 변수는 pthread_cond_destroy함수를 호출하여 해제해줘야 한다.
3. pthread_cond_signal
int pthread_cond_signal(pthread_cond_t *cond);
cond 변수에 신호를 보내어 cond 변수를 기다리고 있는 스레드를 다시 시작시키는 함수이다. 만약 cond 변수를 기다리는 스레드가 없다면 아무 일도 일어나지 않느다. pthread_cond_signal함수는 cond 변수를 기다리는 여러 스레드 중에 단 하나만 다시 시작시킨다. 하지만 어떤 스레드를 시작시킬지는 지정할 수 없다.
4. pthread_cond_broadcast
int pthread_cond_broadcast(pthread_cond_t *cond);
하나의 스레드만 다시 시작시키는 pthread_cond_signal 함수와 다르게 cond 변수를 기다리고 있는 모든 스레드를 다시 시작시킨다.
5. pthread_cond_wait
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
cond 변수가 신호를 받을 때까지 기다리는 함수이다. 이 함수가 실행되면 mutex를 lock을 해제하고 기다린다. 따라서 다른 스레드에서는 mutex변수의 lock을 얻을 수 있다. 그 다음 이 함수를 벗어날 경우 mutex lock을 얻게 된다. 기다리는 시간을 지정할 수 있는 pthread_cond_timedwait도 있다.
예제
이 예제는 1부터 10까지의 숫자를 두 개의 스레드에서 출력한다. 1~3은 1번 스레드가, 4~7은 2번 스레드가, 8~10은 다시 1번 스레드가 실행한다. 1번 스레드가 실행할 부분은 2번 스레드에서 신호를 주어 cond변수를 이용하여 다시시작한다.
소스 코드
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //변수 초기화
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int value = 0; //공유 변수
void *func1(void *arg) { //스레드1이 실행할 함수
while(1) {
pthread_mutex_lock(&mutex); //lock을 걸고
pthread_cond_wait(&cond, &mutex); //기다림
value++; //1 증가시키고
printf("thread1 : %d\n", value); //출력
pthread_mutex_unlock(&mutex); //lock 해제
if(value >= 10) //10을 넘어갈 경우 종료
return NULL;
}
}
void *func2(void *arg) { //스레드2가 실행할 함수
while(1) {
pthread_mutex_lock(&mutex); //lock을 걸고
if(value < 3 || value > 6) { //1번 스레드가 실행할 부분
pthread_cond_signal(&cond); //cond변수를 기다리는 스레드 1번을 다시 시작시킴
}
else { //그 외의 부분은
value++; //1 증가시키고
printf("thread2 : %d\n", value); //출력
}
pthread_mutex_unlock(&mutex); //lock 해제
if(value >= 10)
return NULL;
}
}
int main() {
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, &func1, NULL); //스레드 1 생성
pthread_create(&tid2, NULL, &func2, NULL); //스레드 2 생성
pthread_join(tid1, NULL); //스레드1 리소스 반환
pthread_join(tid2, NULL); //스레드2 리소스 반환
pthread_mutex_destroy(&mutex); //mutex 변수 해제
pthread_cond_destroy(&cond); //cond 변수 해제
return 0;
}
실행 결과
1~3, 8~9는 1번 스레드가 출력하고 4~7은 2번 스레드가 출력하는 것을 볼 수 있다.
'리눅스 시스템 프로그래밍' 카테고리의 다른 글
[Linux] 리눅스 시스템 프로그래밍 exec 계열 함수 (0) | 2021.08.14 |
---|---|
[Linux] 리눅스 시스템 프로그래밍 프로세스(process) 생성과 종료 (0) | 2021.08.13 |
[Linux] Mutex를 이용하여 스레드(Thread) 동기화하기 (0) | 2021.08.11 |
[Linux] 리눅스 시스템 프로그래밍 thread(스레드) 생성과 종료 (0) | 2021.08.06 |
[Linux] 저수준 파일 입출력과 고수준 파일 입출력 (0) | 2021.07.20 |