Implementing Counting Semaphore

  • condition variable을 이용해서 counting semaphore를 구현할 수 있습니다.
  • 각각의 semaphore는 count, condition variable, mutex가 필요합니다.

typedef struct sem_t {
    int count; 
    pthread_mutex_t m;
    pthread_condition_t cv;
} sem_t;


sem_init에서는 mutex와 condition variable의 초기화를 구현합니다.


int sem_init(sem_t *s, int pshared, int value) {
    if (pshared) { errno = ENOSYS /* 'Not implemented'*/; return -1; }

    s->count = value;
    pthread_mutex_init(&s->m, NULL);
    pthread_cond_init(&s->cv, NULL);
    return 0;
}


우리가 구현하는 sem_post에서는 count의 증가가 필요합니다. 또한 condition variable안에 sleep중인 어떤 스레드를 깨워야 합니다. 반드시 mutex를 lock과 unlock하여 한번에 하나의 스레드만 CS에 진입할 수 있도록 해야 합니다.


sem_post(sem_t *s) {
    pthread_mutex_lock(&s->m);
    s->count++;
    pthread_cond_signal(&s->cv); /* See note */
    /* A woken thread must acquire the lock, so it will also have to wait until we call unlock */

    pthread_mutex_unlock(&s->m);
}



우리가 구현하는 sem_wait에서는 semaphore의 count가 0이라면 sleep해야 합니다. sem_post처럼 lock을 이용해 ciritical section을 감싸주어야 합니다. 스레드가 기다릴 필요가 있다면 알려주고 mutex는 unlock이 되어 다른 스레드가 sem_post에 진입하여 sleep에서 깨워주길 기다려야 합니다.


스레드가 깨어났더라도, pthread_cond_wait으로부터 return되기 전에는 lock을 다시 취득해야 합니다. 이렇게 함으로서 잠시 더 기다릴 수 있습니다(예를 들어 sem_post가 끝날 때까지)


sem_wait(sem_t *s) {
    pthread_mutex_lock(&s->m);
    while (s->count == 0) {
        pthread_cond_wait(&s->cv, &s->m); /*unlock mutex, wait, relock mutex */
    }
    s->count--;
    pthread_mutex_unlock(&s->m);
}


잠시!!sem_post가 계속 pthread_cond_signal을 호출하면 sem_wait을 탈출하지 않을까요?


아닙니다! count가 0 이 될때까지는 loop를 통과할 수 없습니다. 사실 이것은 sem_post가 기다리는 스레드가 없어도 반드시 pthread_cond_signal을 호출해야 한다는 것을 의미합니다. 

더 효율적인 구현은 pthread_cond_signal을 필요할때 호출하는 것입니다.


 /* Did we increment from zero to one- time to signal a thread sleeping inside sem_post */
    if (s->count == 1) /* Wake up one waiting thread! */
        pthread_cond_signal(&s->cv);



Other semaphore considerations

  • 실제 세마포어 구현은 공정함과 우선순위를 보장하기 위해서 queue와 scheduling이 포함되어 있습니다.  예를 들면 가장 오래 잠든 스레드의 가장 높은 우선순위를 깨우는 방식 등으로사용됩니다.
  • 또한 sem_init의 고급 사용은 semaphore를 프로세스간에 사용이 가능하게 합니다 우. 한 프로세스 안에 있는 스레드에 대해서만 동작합니다.


Posted by 몰랑&봉봉
,