정체불명의 모모

[c++ / 리눅스] Condition Variable 본문

프로그래밍(c++)

[c++ / 리눅스] Condition Variable

정체불명의 모모 2021. 9. 15. 16:30

오늘은 멀티쓰레드 관련한 내용을 또 가져왔습니다.
역시 게임 개발에 멀티쓰레드가 빠질 수 없군요...

처음 들어보는 Condition Variable

리눅스에서 사용되는 개념인듯 합니다.

유튜브 강의를 찾아봐도 죄다 어째 영어 강의 밖에 없어서 어찌할 바를 모르던 차에...

친절한 분들이 열심히 정리한걸 바탕으로 오늘 포스팅을 하고

이해 해보려 합니다.

Let's go~


Condition Variable(조건 변수)이란?

:  Condition Variable 은 특정 조건을 만족하기를 기다리는 변수라는 의미입니다.

   따라서 이를 이용하여 주로 thread간의 신호 전달을 위해 사용한다.

   하나의 thread가 watiting 중이면 조건을 만족한 thread에서 변수를 바꾸고 signaling 을 통해 깨우는 방식이다.

 

Condition Variable(조건 변수) 사용 방법

: Condition Variable은 앞서 말했 듯 waiting 과 signaling을 사용한다.

  따라서 기본적으로 cond_wait()와 cond_signal() 함수를 사용하게 된다.

  또한 wait와 signal 내부적으로 unlock()과 lock()이 각각 앞 뒤로 있기 때문에 외부를 lock() 과 unlock()으로 감싸야 한다.

 

Condition Variable 함수 정리
  • pthread_cond_init
    : 조건 변수를 초기화 합니다. 이 함수 말고 정적으로 조건 변수를 초기화할 경우에는 PTHREAD_CONT_INITIALIZER 상수를
      이용해서 초기화할 수도 있습니다.
    int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restric attr);​
  • pthread_cond_wait
    : 조건이 참이 될 때까지 대기하는 함수입니다.
      pthread_cond_wait의 두번째 인수는 조건 변수를 보호하기 위한 뮤텍스입니다.
      pthread_cond_wait을 호출하기 전에 전달할 mutex를 이용하여 잠근 후에 이 함수를 호출해야 합니다.
      즉, pthread_cond_wait전에 pthread_mutex_lock을 호출하는데 둘의 mutex는 같아야 한다는 것입니다.
      그러면 이 함수는 호출한 스레드를 조건의 발생을 대기하는 스레들의 목록에 추가하고 뮤텍스를 풀게 됩니다.
    int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex *mutex);
    // 첫번째 인자가 condition 변수이고 , 두번째 인자는 동기화를 할 mutex 입니다.
    호출 순서 pthread_mutex_lock   →   pthread_cond_wait 
  • pthread_cond_signal
    : 대기 중인 스레드에게 signal을 보냅니다.
      현재 pthread_cond_wait으로 대기중인 스레드를 깨우게 되어 다른 스레드가 이후의 작업을 진행할 수 있도록 해줍니다.
      pthread_cond_wait과는 다르게 mutex를 받지 않습니다.
    int pthread_cond_signal(pthread_cond_t *cond);​

pthread 멤버 함수
  • pthread_create(pthread_t *thread, const pthread_attr_t *attr , void *(*start_routine)(void *) , void *arg);
    : 쓰레드 생성을 위해서 사용한다.
      - 1번째 인자 : 아규먼크인 thread는 쓰레드가 성공적으로 생성되었을때 생성된 쓰레드를 식별하기 위해서 사용되는 쓰레드
      - 2번째 인자 : attr은 쓰레드 특성을 지정하기 위해서 사용하며, 기본 쓰레드 특성을 이용하고자 할 경우에 NULL을 사용한다.
      - 3번째 인자 : start_routine는 분기시켜서 실행할 쓰레드 함수이다.
      - 4번째 인자 : arg는 쓰레드 함수 인자이다.( 성공적으로 생성될 경우 0을 리턴한다.)

    실행된 쓰레드에 대해서는 pthread_join 등의 함수를 이용해서 쓰레드 종료때까지 기다려줘야 한다.
    pthread_join은  일종의 fork의 wait과 비슷하게 작동라며, 쓰레드 자원을 해제 해준다.

  • pthread_join(pthread_t th , void **thread_return);
    : 쓰레드 종료시 자원을 회수하는 함수
      pthread_join함수의 리턴값이 0이면 성공, 아니면 실패다.
      pthread_create를 사용한 후 pthread_join , pthread_exit, pthread_detach와 같은 스레드 종료 함수를 
      호출하지 않을 경우, 스레드 실행 중에 main이 종료되어 에러가 발생한다.
      스레드 함수의 리턴값을 thread_return으로 받아올 수 있으나 아래 예제에서는 스레드 함수의 리턴값이 없기 때문에 NULL로 둔다.

     - 1번째 인자 : th는 기다릴(join)할 쓰레드 식별자이다.
     - 2번째 인자 : 아규먼트 thread_return은 쓰레드의 리턴 값이다.
                            thread_return이 NULL이 아닐경우 해다 포인터로 쓰레드 리턴 값을 받아올 수 있다.

  • pthread_mutex_init(pthread_mutex_t *restrict mutex , const pthread_mutexattr_t * restrict attr);
    mutex를 초기화 하는데에는 두 가지 방법이 존재합니다.

    1. 정적으로 할당된 뮤텍스를 초기화하려면 PTHREAD_MUTEX_INITIALIZER 상수를 이용해서 초기화 합니다.
    2. 동적으로 초기화 하려면 pthread_mutex_init 함수를 사용하면 됩니다. mutex를 사용하기 전에 초기화를 시작해야 합니다.

  • pthread_mutex_lock, pthread_mutex_unlock 
    : 이 두함수는 mutex를 이용하여 임계 구역을 진입할때 그 코드 구역을 잠그고 다시 임계 구역이 끝날때 다시 풀어 
      다음 스레드가 진입할 수 있도록 합니다.

     중요한
    pthread_mutex_lock이 어떤 스레드에서 호출되어 lock이 걸렸을때 다른 스레드가 임계구역에 진입하기 위해서
      pthread_mutex_lock을 호출했다면 그 스레드는 이 전의 스레드가 임계 구역을 나올때까지, 즉 pthread_mutex_unlock을 
      할 때까지 기다려야 합니다.

  • pthread_mutex_destroy
    : 만약 뮤텍스를 동적으로 생성(pthread_mutex_init을 이용하여 초기화) 했다면 이 함수를 사용하는 함수가

      pthread_mutex_destroy 입니다.


코드 예제
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

pthread_mutex_t mutex;
int cnt=0;

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

    pthread_mutex_lock(&mutex);		// 여기를 주석 처리해주면 결과가 이상하게 나옴

    //======== 임계 영역 =============
    cnt=0;
    for (i = 0; i <10; i++)
    {
        printf("%s cnt: %d\n", name,cnt);
        cnt++;
        usleep(1);
    }
    //========= 임계 영역 ============
    pthread_mutex_unlock(&mutex); // 여기를 주석 처리해주면 결과가 이상하게 나옴
    
    return 0;
}

int main()
{
    pthread_t thread1,thread2;

    pthread_mutex_init(&mutex,NULL);

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

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

    pthread_mutex_destroy(&mutex);
    
    return 0;
}

mutex_lock을 해준 결과

 

mutex_lock을 해주지 않은 결과


흠... 정리는 했긴 했다만...
정확하게 이해가 가질 않는것 같다

강의를 들어야 겠다..

쓰레드는 왤케 어렵게 느껴지는 걸까낭...


참고 사이트 

https://ju-hy.tistory.com/39

 

Condition Variable이란?

Condition Variable이란? Condition Variable은 특정 조건을 만족하기를 기다리는 변수라는 의미이다. 따라서 이를 이용하여 주로 thread간의 신호 전달을 위해 사용한다. 하나의 thread가 waiting 중이면 조건

ju-hy.tistory.com

https://jungwoong.tistory.com/92

 

[c++] condition variable(조건 변수)

 이번 글에서는 std::condition_variable에 대해서 설명드립니다. 설명 및 기본 동작 std::condition_variable  condition_variable 클래스는 다른 스레드가 공유 변수를 수정하고 condition_variable로 통지할..

jungwoong.tistory.com

https://reakwon.tistory.com/99

 

[리눅스] 조건변수를 통한 스레드 동기화 설명, 예제(pthread_cond_wait, pthread_cond_signal)와 생산자-소

조건 변수 조건 변수를 설명하기 전에 다음과 같은 상황이 발생했다고 칩시다. 먼저 스레드 2개가 존재합니다. 저는 짧은 코드를 좋아하므로 아주 간단한 역할을 하는 2개의 쓰레드를 생성했습

reakwon.tistory.com

http://www.digipine.com/index.php?mid=clan&document_srl=584 

 

C/C++ Language - [Linux] Pthread 사용법, Thread 동기화 총정리

Pthread API Reference 1.1. pthread_create int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); 쓰레드 생성을 위해서 사용한다. 첫번째 아규먼트인 thread 는 쓰레드가 성공적

www.digipine.com

https://hydroponicglass.tistory.com/298

 

[C, C++] Pthread로 스레드 구현

목적 a와 b를 각각 무한히 출력하는 가장 기본적인 스레드 A와 B를 구현한다. 스레드 구현 헤더파일 #include #include 스레드 구현부 void *threadA() { while(1) { printf("a\n"); } } void *threadB() { while(..

hydroponicglass.tistory.com

 

Comments