Linuxでの読み書きロックの使い方

読み書きロックの概要

読み書きロックはミューテックスの進化版で、読込ロックを取得した場合、複数スレッドが並列/並行で読み込み操作を実行可能です。これにより読み込み処理時のパフォーマンスが向上します。一方で書き込みロックは排他制御を行うため、ミューテックスと同様にシリアライズされます。

Linuxではpthread_rwlock_t型で定義されます。この型を用いてロックオブジェクトを宣言します:

pthread_rwlock_t data_lock;

ロックオブジェクトは以下の情報を保持します:

  • ロック状態(ロック中/解放中)
  • 操作種別(読込/書込)
  • ロックを保持しているスレッドID

基本的な使用方法はミューテックスと同様で、共有リソースを特定し、臨界セクションの開始時にロック(読込/書込)、終了時にアンロックを行います。

読み書きロックの特性

  • 読込ロックは共有可能:複数スレッドが同時に読込操作を実行可能
  • 書込ロックは排他制御:1スレッドのみが書き込み許可
  • 書込優先:既存の読込ロックが存在する場合でも書込ロック要求が優先
  • 読込中は書込不可、書込中は読込不可

適用ケース

すべてのスレッドが書き込み処理しか行わない場合はミューテックスと同等の性能になります。読み込み処理が多数存在する場合に性能向上効果が顕著です。

関数リファレンス

Linuxが提供する読み書きロック関数のプロトタイプ:

#include <pthread.h>
pthread_rwlock_t data_lock;

// 初期化
int pthread_rwlock_init(pthread_rwlock_t *restrict lock, const pthread_rwlockattr_t *restrict attr);

// 破棄
int pthread_rwlock_destroy(pthread_rwlock_t *lock);

引数:

  • lock:ロックオブジェクトのアドレス(出力用)
  • attr:属性(NULLでデフォルト)
// 読込ロック取得
int pthread_rwlock_rdlock(pthread_rwlock_t *lock);
// ノンブロッキング読込ロック
int pthread_rwlock_tryrdlock(pthread_rwlock_t *lock);
// 書込ロック取得
int pthread_rwlock_wrlock(pthread_rwlock_t *lock);
// ノンブロッキング書込ロック
int pthread_rwlock_trywrlock(pthread_rwlock_t *lock);
// ロック解除(読込/書込共通)
int pthread_rwlock_unlock(pthread_rwlock_t *lock);

使用例

8スレッドがグローバル変数を操作するサンプル。3スレッドは不定期に書き込み、5スレッドは不定期に読み込みを行います。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

int counter = 0;
pthread_rwlock_t data_lock;

// 書き込みスレッド
void* incrementCounter(void* arg)
{
    while(1)
    {
        pthread_rwlock_wrlock(&data_lock);
        counter += rand() % 10 + 1;
        printf("値更新: %d (スレッドID: %ld)\n", counter, pthread_self());
        pthread_rwlock_unlock(&data_lock);
        usleep(rand() % 200);
    }
    return NULL;
}

// 読み込みスレッド
void* displayCounter(void* arg)
{
    while(1)
    {
        pthread_rwlock_rdlock(&data_lock);
        printf("現在値: %d (スレッドID: %ld)\n", counter, pthread_self());
        pthread_rwlock_unlock(&data_lock);
        usleep(rand() % 150);
    }
    return NULL;
}

int main()
{
    pthread_rwlock_init(&data_lock, NULL);
    
    pthread_t writers[3], readers[5];
    
    for(int i=0; i<3; i++) pthread_create(&writers[i], NULL, incrementCounter, NULL);
    for(int i=0; i<5; i++) pthread_create(&readers[i], NULL, displayCounter, NULL);
    
    for(int i=0; i<3; i++) pthread_join(writers[i], NULL);
    for(int i=0; i<5; i++) pthread_join(readers[i], NULL);
    
    pthread_rwlock_destroy(&data_lock);
    return 0;
}

タグ: pthread linux カーネルプログラミング スレッド同期 読み書きロック

7月15日 19:55 投稿