CodeZine(コードジン)

特集ページ一覧

pthreadについて(同期)

pthreadの同期方法

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2007/12/12 14:00
目次

3.同期(3/4):read/write lock

3.5 read/write lock

 スレッドが保護対象を参照する時、変更しようとしているスレッドはロックされていないといけませんが、参照しようとしている他のスレッドはロックされていなくてもいいはずです。逆に変更しようとしているスレッドが複数居ても、各スレッドでロックされていないといけません。

 mutexやspinでは、保護対象の情報に対して上記のような柔軟性を持っておらず、全スレッドで排他されてしまい、ひいてはボトルネックになります。

 キャッシュ情報へのアクセス等は情報の参照だけであれば複数スレッドによる同時処理でも問題ないはず。それを実現するのが、read/write lockです。

  • int pthread_rwlock_init( pthread_rwlock_t * __rwlock, __const pthread_rwlockattr_t * __attr )
  • int pthread_rwlock_destroy( pthread_rwlock_t * __rwlock )
  • int pthread_rwlock_rdlock( pthread_rwlock_t * __rwlock )
  • int pthread_rwlock_tryrdlock( pthread_rwlock_t * __rwlock )
  • int pthread_rwlock_timedrdlock( pthread_rwlock_t * __rwlock, __const struct timespec * __abstime )
  • int pthread_rwlock_wrlock( pthread_rwlock_t * __rwlock )
  • int pthread_rwlock_trywrlock( pthread_rwlock_t * __rwlock )
  • int pthread_rwlock_timedwrlock( pthread_rwlock_t * __rwlock, __const struct timespec * __abstime )
  • int pthread_rwlock_unlock( pthread_rwlock_t * __rwlock )

 pthread_rwlockattr_t * __attrはspinと同様、プロセスをまたいで使用するかの属性を設定します。使用しない場合はNULLを設定し、自プロセス内のスレッドにのみ使用する設定になります。

 下記サンプルプログラムを動かします。write_funcはwrite_countを変更し、read_funcはwrite_countを参照しています。read_funcのカウンタは高速で進みますが、write_funcは1秒毎でwrite_lockします。write_lockされるとread_funcのカウンタが止まり、write_funcがunlockすると、read_funcが再開しますが、カウンタの末尾のアルファベットが変更されています。

 なお、write_funcはread_funcの生存確認をpthread_killで行ってますが、この関数の説明は別称で行います。ちなみにスレッド生成の際、怠けて数値を直接変数として設定しているため、ワーニングが出ます。手を抜いてすいません。

rwlock_test.c
/* gcc rwlock_test.c -o rwlock_test -g -W -Wall -lpthread */
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#define LOOP_CNT 20000000
pthread_rwlock_t lock;
int write_count = 0x41;  /* 'A' */
pthread_t id[4];
void * read_func ( void * arg );
void * write_func( void * arg );

int main( ) {

    pthread_rwlock_init( &lock, 0 );

    pthread_create( &id[0], 0, read_func,  ( void * )0 );
    pthread_create( &id[1], 0, read_func,  ( void * )1 );
    pthread_create( &id[2], 0, read_func,  ( void * )2 );
    pthread_create( &id[3], 0, write_func, ( void * )3 );
    pthread_join( id[0], 0 );
    pthread_join( id[1], 0 );
    pthread_join( id[2], 0 );
    pthread_join( id[3], 0 );

    pthread_rwlock_destroy( &lock );
    return 0;
}

void * read_func( void * arg ) {
    int index = ( int * )arg;
    int count = 0;
    int i;
    for( i = 0; i < LOOP_CNT; i ++ ) {
        pthread_rwlock_rdlock( &lock );
        count ++;
        if( count % 1000 == 0 ) {
            printf( "\t\t%d %*.*s%5d[%c]\r",
                index, index + 1, index + 1,
                "\t\t\t", count / 1000, write_count );
        }
        pthread_rwlock_unlock( &lock );
    }
    printf( "thread %d End!!\n", index );
    return 0;
}

void * write_func( void * arg ) {
    int index = ( int * )arg;
    int i;
    for( i = 0; ; i ++ ) {
        sleep( 1 );
        if( pthread_kill( id[0], 0 )
        &&  pthread_kill( id[1], 0 )
        &&  pthread_kill( id[2], 0 )) {
            break;
        }
        pthread_rwlock_wrlock( &lock );
        printf( "\nnow wrlock!! %c -> %c\n",
            write_count, write_count + 1 );
        write_count ++;
        sleep( 1 );
        pthread_rwlock_unlock( &lock );
    }
    printf( "thread %d End!!\n", index );
    return 0;
}

 尚、read/write lockもそれ程難しくなく自作できます。

 init/read lock/read unlock/write lock/write unlock を自作しました。プログラムが多少長いので詳細はダウンロードファイル(wrap_rwlock.c)を参照願います。詳細は下記のような感じです。

  • read_lock
  • write中かwrite待ちのスレッドが居る場合はサスペンドします。
  • read_unlock
  • read中が居ない且つwrite待ちが居る場合はwrite待ちスレッドにシグナルを発行します。
  • write_lock
  • write中かread中が居る場合はサスペンドします。
  • write_unlock
  • write待ちが居ればwrite待ちスレッドに、write待ちが居なくてread待ちが居る場合はread待ちスレッドにシグナルを発行します。

 実際にプログラム(wrap_rwlock.c)を動かした結果もpthread_rwlock_*系関数と同じ動きになります。destroyやtrylockの自作を試しても良いと思います。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:pthreadについて

もっと読む

著者プロフィール

  • 赤松 エイト(エイト)

    (株)DTSに勤てます。 WebアプリやJavaやLL等の上位アプリ環境を密かに憧れつつも、ず~っとLinuxとかHP-UXばかり、ここ数年はカーネル以上アプリ未満のあたりを行ったり来たりしています。 mixiもやってまして、こちらは子育てとか日々の日記メインです。

あなたにオススメ

All contents copyright © 2005-2022 Shoeisha Co., Ltd. All rights reserved. ver.1.5