相互排除変数と条件変数

  • スレッドやプロセス間でデータを共有するためには、同期操作が必要

  • 相互排除変数と条件変数は、同期操作のための基本機能

  • Posixの相互排除変数と条件変数は、プロセス内の複数のスレッド間の同期に利用できる

  • Posixでは、相互排除変数や条件変数がプロセス間の共有メモリ上に置かれている場合、それらをプロセス間の同期に用いることを許す

  • 相互排除変数は、コード内のcritical regionを保護する。

  • 相互排除変数は、pthread_mutex_t型の変数として宣言される。


  • 相互排除変数のロックとアンロックのための関数

    #include <pthread.h>
    
    int pthread_mutex_lock(pthread_mutex_t *mptr);
    int pthrea_mutex_trylock(pthread_mutex_t *mptr);
    int pthread_mutex_unlock(pthread_mutex_t *mptr);
    
    戻り値:関数とも、成功なら0、エラーなら正のExxx値

  • pthread_mutex_lockは、他のスレッドによってすでにロックされている相互排除変数をロックしようとした場合、そのロックが解除されるまでブロックする。

  • pthread_mutex_trylockは、指定した相互排除変数が既にロックされていた場合EBUSYを返す非ブロッキング関数


  • 相互排除変数により保護されるのは、critical region内で操作される共有データ。




  • 生産者-消費者問題

  • Posix,System V メッセージキューを生産者-消費者問題に適用した場合、カーネルが同期処理をする

  • 生産者と消費者の間のIPCに共有メモリを用いる場合には、生産者と消費者の間に何らかの明示的な同期操作が必要


  • 条件変数:待ちと通知

  • 相互排除変数は「ロック」を目的とし、条件変数は「待ち」を目的とする

  • 条件変数は、pthread_cond_t型の変数


  • pthread_cond_t型の変数を操作するのが、pthread_cond_waitとpthread_cond_signal。

    #include <pthread.h>
    
    int pthread_cond_wait(pthread_cond_t *cptr,pthread_mutex_t *mptr);
    int pthread_cond_signal(pthread_cond_t *cptr);
    
    戻り値:関数とも成功なら0、エラーなら正のExxx値

    pthread_cond_waitは、

  • 1.相互排除変数mptrがアンロックされる

  • 2.条件変数cptrに対してpthread_cond_signalが呼び出されるまで、呼び出したスレッドがスリープ状態におかれる

  • 3.制御を戻す前に相互排除変数mptrをロックする

  • //Producer-Consumer Pettern
    //生産者-消費者 パターン
    #include <pthread.h>
    #include <stdio.h>
    
    #define MAX_QUEUE_SIZE 3
    
    int queue[MAX_QUEUE_SIZE];
    int head = 0;
    int tail = 0;
    int count = 0;
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_cond_t cond_cons = PTHREAD_COND_INITIALIZER;
    pthread_cond_t cond_prod = PTHREAD_COND_INITIALIZER;
    
    
    void
    enqueue(int n)
    {
        pthread_mutex_lock(&mutex);
        while (count >= MAX_QUEUE_SIZE) {
            pthread_cond_wait(&cond_prod,&mutex);
        }   
    
        queue[tail] = n;
        tail = (tail + 1) % MAX_QUEUE_SIZE;
        count++;
    
        pthread_cond_signal(&cond_cons);
        pthread_mutex_unlock(&mutex);
    }
    
    int
    dequeue()
    {
        pthread_mutex_lock(&mutex);
    
        while (count <= 0) {
            pthread_cond_wait(&cond_cons,&mutex);
        }
    
        int elem = queue[head];
        head = (head + 1) % MAX_QUEUE_SIZE;
        count--;
       
        pthread_cond_signal(&cond_prod);
        pthread_mutex_unlock(&mutex);
        return elem;
    }
    
    void *
    consumer(void *arg)
    {
        int n;
        for (;;) {
            n = dequeue();
            printf("dequeued :%d\n",n);
            sleep(2);
        }
        return NULL;
    }
    
    void *
    producer(void *arg)
    {
        int i;
        for (i = 0; ; i++) {
            enqueue(i);
            printf("enqueued :%d\n",i);
            sleep(1);
        }
        return NULL;
    }
    
    int
    main()
    {
        int i;
        pthread_t cons_thread;
        pthread_t prod_thread;
       
        /* Creates threads */
       
        pthread_create(&cons_thread, NULL, consumer, NULL);
        pthread_create(&prod_thread, NULL, producer, NULL);
       
    
        /* Join threads */
        pthread_join(cons_thread, NULL);
        pthread_join(prod_thread, NULL);
    
        printf("Exit!");
    
        return 0;
    }
    



    条件変数: 制限時間付きの待ちとブロードキャスト

    複数のスレッドを起こす場合、pthread_cond_broadcastを用いる。

    #include <pthread.h>
    
    int pthread_cond_broadcast(pthread_cond_t *cptr);
    int pthread_cond_timedwait(pthread_cond_t *cptr,
                               pthread_mutex_t *mptr,
                               const struct timespec *abstime);
    
    戻り値:2関数とも成功なら0、エラーなら正のExxx値

    pthread_cond_timewaitは、呼び出したスレッドがブロックする時間に制限を設けることが出来る。
    abstimeは、timespec構造体。

    struct timespec {
        time_t tv_spec; /* 秒 */
        long tv_nsec; /* ナノ秒 */ 
    };

    abstimeは、絶対時刻であり、時間の差ではない。abstimeには、関数から戻るシステム時刻を指定する。


    相互排除変数と条件変数の属性

    相互排除変数や条件変数の生成と破壊を行う関数

    #include <pthread.h>
    
    int pthread_mutex_init(pthread_mutex_t *mptr,
                           const pthread_mutexattr_t *attr);
    
    int pthread_mutex_destroy(pthread_mutex_t *mptr);
    
    int pthread_cond_init(pthread_cond_t *cptr,
                          const pthread_condattr_t *attr);
    
    int pthread_cond_destroy(pthread_cond_t *cptr);
    
    
    戻り値:4関数とも成功なら0、エラーなら正のExxx値