APUE学習ノート——11スレッド同期、反発ロック、スピンロック、条件変数


スレッド同期
同じプロセスに属する異なるスレッドは共有メモリであるため、実行中にデータの一貫性を考慮する必要があります.
仮に、プロセスに変数i=0があり、スレッドAがi++を実行し、スレッドBがi++を実行するとしたら、最終iの値はいくらですか?i=2に違いないようです.実はそうではありません.スレッド同期を考慮していない場合、iの値は1である可能性があります.まず、自己加算動作のプロセスを考慮します.aは、まずメモリ内のiの値をレジスタにcopyします.b、レジスタ中のiのcopyを自己加算する.c,レジスタに自己加算された結果をメモリに返す.例に戻ると、スレッドAがabcの3つのステップを実行し、スレッドBが実行者の3つのステップを実行した場合、結果は2であるべきである.しかし、自己加算は原子操作ではなく、実行過程がa(A)、a(B)、b(A)、b(B)、c(A)、c(B)である場合、ABはiの原値i=0 copyをレジスタに自己加算し、結果1を得た後、メモリに値1を付与iが、iの結果は1となる.
上記の望ましくない結果(i=2ではなくi=1)が現れる可能性があるのは、i++が原子操作ではないためである.この問題を解決するために、反発ロックが導入される.
反発ロックMutexes
反発ロックはpthreadsの反発インタフェースを通じて、データがある時間に1つのスレッドしかアクセスできないことを保証します.
反発ロックの使用手順は,1)共有リソースにアクセスする前にロックをかけ,2)共有リソースにアクセスする,3)アクセスが加速した後にロックを解除する.(この過程で反発量はロックの役割を果たす)
反発量使用構造体pthread_mutex_tは、使用するインタフェースが以下のように表示される.
反発量の初期化と破棄:

    
    
    
    
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t*restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
Both return: 0 if OK, error number on failure

動的に作成された反発量mutexを使用する必要があります
pthread_mutex_destroy,
静的に反発量を作成する場合,直接mutex=
PTHREAD_MUTEX_INITIALIZERは起動せずに初期化する
pthread_mutex_init
で行ないます.
パラメータattrは反発量の属性を表す.
ロックとロック解除:
    

   
   
   
   
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex,const struct timespec *restrict tsptr);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
All return: 0 if OK, error number on failure

使用
pthread_mutex_lock
場合、反発量が他のスレッドにロックされている場合、ブロックされ、その反発量がロック解除され、反発量がロックされることが分かった.
 
使用
pthread_mutex_trylock
の場合、反発量が他のスレッドにロックされている場合
を選択すると、関数はエラーを返します.ロックされていない場合は、反発量にロックされます.
使用
pthread_mutex_timedlock
の場合は、ロックをかけてみて、ブロックしてみます(最大は時点tsptrまでブロックします).tsptrでロックができない場合は、エラーが返されます.tsptrについては、3 min待つなどの時点で、結果としてtsptrは現在の時間に3 min加算されます.
デッドロックとデッドロックの回避
デッドロックが発生した場合:
1)スレッドは同一の反発量に対して2回ロックし、以下のような状況である.

    
    
    
    
pthread_mutex_lock(mutex);
pthread_mutex_lock(mutex);
pthread_mutex_unlock(mutex);
pthread_mutex_unlock(mutex);

2行目にブロックが発生し、デッドロックが発生します.
2)複数の反発量があり、異なるスレッドがそれぞれ1つの反発量をロックし、他の反発量を要求するときにブロックされる.

    
    
    
    
//thread A
pthread_mutex_lock(mutex1);
pthread_mutex_lock(mutex2);
pthread_mutex_unlock(mutex2);
pthread_mutex_unlock(mutex1);
//thread B
pthread_mutex_lock(mutex2);
pthread_mutex_lock(mutex1);
pthread_mutex_unlock(mutex1);
pthread_mutex_unlock(mutex2);
A mutex1, mutex2 ,B mutex2.   B mutex1 , A 。

    , , , 。
    , , 。 pthread_mutex_lock ( mutex1 ); pthread_mutex_lock ( mutex2 );   。
    , :

    
    
    
    
struct foo {
    int f_count;
    pthread_mutex_t f_lock;
    int f_id;
    /* ... more stuff here ... */
};

   

    , 。
    :
    1) , 。
    2) ( ) ,
    3) , 。
    , , , , 。 。
    ( ):

    
    
    
    
#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlockattr_t*restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
Both return: 0 if OK, error number on failure

    
    
    
    
#include <pthread.h>
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
All return: 0 if OK, error number on failure

     
     
     
     
#include <pthread.h>
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
Both return: 0 if OK, error number on failure

      
      
      
      
#include <pthread.h>
#include <time.h>
int pthread_rwlock_timedrdlock(pthread_rwlock_t *restrictrwlock,const struct timespec*restrict tsptr);
int pthread_rwlock_timedwrlock(pthread_rwlock_t *restrictrwlock,const struct timespec *restric ttsptr);

, 。

    。
    :pthread_cond_t 。
    :

    
    
    
    
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);
Both return: 0 if OK, error number on failure
。 PTHREAD_COND_INITIALIZER 。

    
    
    
    
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,
const struct timespec * restrict tsptr );
pthread_cond_wait
1) mutex
2) ,
3) mutex。

pthread_cond_timedwait tsptr , 3min , tsptr 3min


    
    
    
    
#include <pthread.h>
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
Both return: 0 if OK, error number on failure
Example:

    
    
    
    
#include <pthread.h>
struct msg {
struct msg *m_next;
    /* ... more stuff here ... */
};
struct msg *workq;
pthread_cond_t qready = PTHREAD_COND_INITIALIZER;
pthread_mutex_t qlock = PTHREAD_MUTEX_INITIALIZER;
void
process_msg(void)
{
    struct msg *mp;
    for (;;) {
        pthread_mutex_lock(&qlock);
        while (workq == NULL)
            pthread_cond_wait(&qready, &qlock);
        mp = workq;
        workq = mp->m_next;
        pthread_mutex_unlock(&qlock);
        /* now process the message mp */
    }
}
void
enqueue_msg(struct msg *mp)
{
    pthread_mutex_lock(&qlock);
    mp->m_next = workq;
    workq = mp;
    pthread_mutex_unlock(&qlock);
    pthread_cond_signal(&qready);
}

Spin lock

    。 。 , , 。 , , , , 。 
    。 。 。
    :

    
    
    
    
#include <pthread.h>
int pthread_spin_init(pthread_spinlock_t *lock,intpshared);
int pthread_spin_destroy(pthread_spinlock_t *lock);
Both return: 0 if OK, error number on failure
    

    
    
    
    
#include <pthread.h>
int pthread_spin_lock(pthread_spinlock_t *lock);
int pthread_spin_trylock(pthread_spinlock_t *lock);
int pthread_spin_unlock(pthread_spinlock_t *lock);
All return: 0 if OK, error number on failure

Barriers

    pthread_barrier_   , , , 。
    :

    
    
    
    
#include <pthread.h>
int pthread_barrier_init(pthread_barrier_t *restrictbarrier,const pthread_barrierattr_t *restrict attr,unsigned int count);
int pthread_barrier_destroy(pthread_barrier_t *barrier);
Both return: 0 if OK, error number on failure
count 。

    
    
    
    
#include <pthread.h>
int pthread_barrier_wait(pthread_barrier_t *barrier);
Returns: 0 orPTHREAD_BARRIER_SERIAL_THREADif OK, error number on failure
pthread_barrier_wait  , 。
,8 (count=0), pthread_barrier_wait   , ( ) , 8 ,   pthread_barrier_wait   。