SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

pthreadについて

pthreadについて(シグナル・バリア等)

スレッドによるシグナルの利用法、バリア、それ以外の話題等


  • X ポスト
  • このエントリーをはてなブックマークに追加

13. mutex_type

 3章および9章で少し述べましたが、mutexには属性を持つことができます。主にスケジューリングに関する属性について説明してきましたが、それ以外に、mutexのロック時の挙動に対してタイプを設定することができます。

13.1 種類

 mutexに設定できるタイプは下記4タイプあります。それぞれの特徴は下記の通りです。

表1 タイプ一覧
タイプ ロック済みmutexの再ロック 未ロックmutexのアンロック 備考
PTHREAD_MUTEX_NORMAL デッドロック 未定 初期値、条件変数と併用可能
PTHREAD_MUTEX_RECURSIVE 内部カウンタ 1増加 内部カウンタ 1減少 内部カウンタ0のアンロックはエラー
PTHREAD_MUTEX_ERRORCHECK エラー発生 エラー発生  
PTHREAD_MUTEX_DEFAULT 未定 未定 PTHREAD_MUTEX_NORMALと同じ振る舞い

 なお、pthread_cond系の関数と一緒に使用する場合、タイプはPTHREAD_MUTEX_NORMALでないといけません。次章で各タイプのサンプルで動きを見ます。

13.2 サンプルと動作結果

 PTHREAD_MUTEX_NORMAL についてですが、これは今まで沢山使用してきたmutexのことです。PTHREAD_MUTEX_DEFAULT は実装依存ですが、 PTHREAD_MUTEX_NORMAL と同じ動きをするといっても過言ではないでしょう。下記は私の環境での<pthread.h>です。

/usr/include/pthread.h 抜粋
enum {
・・・
  PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
・・・
};

 PTHREAD_MUTEX_RECURSIVE のサンプルを動かした結果は下記の通りです。main関数でロックしている時にスレッドでロックしようとしてもサスペンド状態になります。つまりあくまで同一スレッド内で内部カウンタが作動していて、同一スレッド内でアンロックがすべて終わらないと他スレッドのロックが行われないということが分かります。

mutex_recursive.c
/* gcc mutex_recursive.c -o mutex_recursive -g -W -Wall -lpthread */
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

pthread_mutex_t mutex;
void * func( void * arg );

int main( ) {

    pthread_t           id = 0;
    pthread_mutexattr_t attr;
    int                 status, i;

    pthread_mutexattr_init( &attr );
    status = pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
    printf( "in main, pthread_mutexattr_settype:[%d]\n", status );
    status = pthread_mutex_init( &mutex, &attr );
    printf( "in main, pthread_mutex_init:[%d]\n", status );

    for( i = 0, status = 0; i < 4 && status == 0; i ++ ) {
        status = pthread_mutex_lock( &mutex );
        printf( "in main, %d pthread_mutex_lock:[%d][%s]\n",
            i + 1, status, strerror( status ));
        sleep( 1 );
    }

    status = pthread_create( &id, 0, func, 0 );
    printf( "in main, pthread_create:[%d]\n", status );
    sleep( 1 );
    for( i = 0, status = 0; i < 5 && status == 0; i ++ ) {
        status = pthread_mutex_unlock( &mutex );
        printf( "in main, %d pthread_mutex_unlock:[%d][%s]\n",
            i + 1, status, strerror( status ));
        sleep( 1 );
    }

    pthread_join( id, 0 );
    pthread_mutex_destroy( &mutex );
    return 0;
}

void * func( void * arg ) {
    ( void )arg;

    int status, i;
    for( i = 0, status = 0; i < 4 && status == 0; i ++ ) {
        status = pthread_mutex_lock( &mutex );
        printf( "in func, %d pthread_mutex_lock:[%d][%s]\n",
            i + 1, status, strerror( status ));
        sleep( 1 );
    }
    for( i = 0, status = 0; i < 5 && status == 0; i ++ ) {
        status = pthread_mutex_unlock( &mutex );
        printf( "in func, %d pthread_mutex_unlock:[%d][%s]\n",
            i + 1, status, strerror( status ));
        sleep( 1 );
    }
    return 0;
}
guest $./mutex_recursive
in main, pthread_mutexattr_settype:[0]
in main, pthread_mutex_init:[0]
in main, 1 pthread_mutex_lock:[0][Success]
in main, 2 pthread_mutex_lock:[0][Success]
in main, 3 pthread_mutex_lock:[0][Success]
in main, 4 pthread_mutex_lock:[0][Success]
in main, pthread_create:[0]
in main, 1 pthread_mutex_unlock:[0][Success]
in main, 2 pthread_mutex_unlock:[0][Success]
in main, 3 pthread_mutex_unlock:[0][Success]
in main, 4 pthread_mutex_unlock:[0][Success]
in func, 1 pthread_mutex_lock:[0][Success]
in main, 5 pthread_mutex_unlock:[1][Operation not permitted]
in func, 2 pthread_mutex_lock:[0][Success]
in func, 3 pthread_mutex_lock:[0][Success]
in func, 4 pthread_mutex_lock:[0][Success]
in func, 1 pthread_mutex_unlock:[0][Success]
in func, 2 pthread_mutex_unlock:[0][Success]
in func, 3 pthread_mutex_unlock:[0][Success]
in func, 4 pthread_mutex_unlock:[0][Success]
in func, 5 pthread_mutex_unlock:[1][Operation not permitted]
guest $

 PTHREAD_MUTEX_ERRORCHECK は、PTHREAD_MUTEX_RECURSIVE のソースファイルと異なる点は下記の通り、kindの値だけです。

guest $ diff mutex_recursive.c mutex_check.c
1c1
< /* gcc mutex_recursive.c -o mutex_recursive -g -W -Wall -lpthread */
---
> /* gcc mutex_check.c -o mutex_check -g -W -Wall -lpthread */
18c18
<     status = pthread_mutexattr_settype( &attr,
 PTHREAD_MUTEX_RECURSIVE );
---
>     status = pthread_mutexattr_settype( &attr,
 PTHREAD_MUTEX_ERRORCHECK );
guest $

 しかし動かすと、2回目のロックおよびアンロックでエラーが出力されます。同一スレッドでの二重ロック・二重アンロックのみエラーを検出し、他スレッドはロック待ちになっています。

guest $ ./mutex_check
in main, pthread_mutexattr_settype:[0]
in main, pthread_mutex_init:[0]
in main, 1 pthread_mutex_lock:[0][Success]
in main, 2 pthread_mutex_lock:[35][Resource deadlock avoided]
in main, pthread_create:[0]
in main, 1 pthread_mutex_unlock:[0][Success]
in func, 1 pthread_mutex_lock:[0][Success]
in main, 2 pthread_mutex_unlock:[1][Operation not permitted]
in func, 2 pthread_mutex_lock:[35][Resource deadlock avoided]
in func, 1 pthread_mutex_unlock:[0][Success]
in func, 2 pthread_mutex_unlock:[1][Operation not permitted]
guest $

13.3 所感

 正直言ってそれ程実用性はありません。条件変数との併用を考えると、mutexのタイプは初期値にならざるを得ません。しかし単一スレッド内でデッドロックを行っているかチェックする場合には使えそうな機能だと思います。

次のページ
14. joinの注意点

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
pthreadについて連載記事一覧

もっと読む

この記事の著者

赤松 エイト(エイト)

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

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/1973 2008/08/20 16:01

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング