§1 pthread mutex

  • pthread mutexには、「fast(速い)」、「recursive(再帰的な)」、「error checking(エラー検査を行なう)」の三つの属性がある。
  • pthread_mutex_initにてmutexattrを指定しない限り、デフォルトでは「fast(速い)」属性のミューテックスとなる。
  • pthread_mutex_tを静的に初期化する場合は、PTHREAD_MUTEX_INITIALIZERを使用する。
    • この場合、「fast(速い)」ミューテックスとして初期化される。
    • 「recursive(再帰的な)」ミューテックスとして初期化したい場合はPTHREAD_RECURSIVE_MUTEX_INITIALIZER_NPを使用する。
    • 「error checking(エラー検査を行なう)」ミューテックスとして初期化したい場合はPTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NPを使用する。
  • ミューテックスに入るときはpthread_mutex_lock、出るときはpthread_mutex_unlockを用いる。
  • pthread_mutex_lockの代わりにpthread_mutex_trylockをコールすると、ミューテックスがロックされている場合(他のスレッドがミューテックスに入っている場合)は、待機せず即座に呼び元に処理が戻る(このときエラーコードEBUSYを返す)。
  • プロセス間での同期を行う場合にはセマフォを使う

§2 使用例

// gcc -pthread -std=c99

#include <stdio.h>
#include <pthread.h>
#include <time.h>

// ミューテックスオブジェクト
pthread_mutex_t mutex;
// pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 

#define THREAD_COUNT (10)

// ワーカースレッドのオブジェクト格納用の配列
pthread_t threads[THREAD_COUNT];

// ワーカースレッドからアクセスされる変数
int global_value;


//
// ミリ秒単位のsleep
//
int msleep( int milliseconds )
{
  struct timespec t;

  t.tv_sec  =   milliseconds / 1000;
  t.tv_nsec = ( milliseconds % 1000 ) * 1000000;

  return nanosleep( &t, NULL );
}

//
// ワーカースレッド
//
void* worker_thread( void* param )
{
  printf( "ThreadID: %x, started\n", pthread_self() );

  // 同じ処理を繰り返す
  for ( ;; )
  {
    printf( "ThreadID: %x, wait for  resource\n", pthread_self() );

    // ミューテックスに入る
    pthread_mutex_lock( &mutex );

    printf( "ThreadID: %x, access to resource\n", pthread_self() );

    // global_valueをインクリメントする(1回あたり250ミリ秒費やす)
    int work_value = global_value;

    msleep( 250 );

    work_value++;

    global_value = work_value;

    printf( "ThreadID: %x, release   resource\n", pthread_self() );

    // ミューテックスを出る
    pthread_mutex_unlock( &mutex );

    msleep( 100 );
  }

  return NULL;
}

//
// 主スレッド
//
int main( void )
{
  printf( "mutex sample start\n" );

  // ミューテックスオブジェクトを初期化する
  // (属性はデフォルトのものを使用する)
  pthread_mutex_init( &mutex, NULL );

  // 処理を始める前の値を表示
  global_value = 0;

  printf( "initial global_value: %d\n", global_value );


  // ワーカースレッドを10本作成し、50ミリ秒おきに起動
  for ( int index = 0; index < THREAD_COUNT; index++ )
  {
    pthread_create( &threads[index], NULL, worker_thread, NULL );

    msleep( 50 );
  }

  // 主スレッドは3秒間待機する
  msleep( 3000 );

  // 全ワーカースレッドを中断する
  for ( int index = 0; index < THREAD_COUNT; index++ )
  {
    pthread_cancel( threads[index] );

    printf( "ThreadID: %x, canceled\n", threads[index] );
  }

  // 処理を行った後の値を表示
  printf( "after global_value: %d\n", global_value );

  // ミューテックスオブジェクトを破棄する
  pthread_mutex_destroy(&mutex);

  return 0;
}
実行例
mutex sample start
initial global_value: 0
ThreadID: b7e14b90, started
ThreadID: b7e14b90, wait for  resource
ThreadID: b7e14b90, access to resource
ThreadID: b7613b90, started
ThreadID: b7613b90, wait for  resource
ThreadID: b6e12b90, started
ThreadID: b6e12b90, wait for  resource
ThreadID: b6611b90, started
ThreadID: b6611b90, wait for  resource
ThreadID: b5e10b90, started
ThreadID: b5e10b90, wait for  resource
ThreadID: b7e14b90, release   resource
ThreadID: b7613b90, access to resource
ThreadID: b560fb90, started
ThreadID: b560fb90, wait for  resource
ThreadID: b4e0eb90, started
ThreadID: b4e0eb90, wait for  resource
ThreadID: b7e14b90, wait for  resource
ThreadID: b460db90, started
ThreadID: b460db90, wait for  resource
ThreadID: b3e0cb90, started
ThreadID: b3e0cb90, wait for  resource
ThreadID: b360bb90, started
ThreadID: b360bb90, wait for  resource
ThreadID: b7613b90, release   resource
ThreadID: b6e12b90, access to resource
ThreadID: b7613b90, wait for  resource
ThreadID: b6e12b90, release   resource
ThreadID: b6611b90, access to resource
ThreadID: b6e12b90, wait for  resource
ThreadID: b6611b90, release   resource
ThreadID: b5e10b90, access to resource
ThreadID: b6611b90, wait for  resource
ThreadID: b5e10b90, release   resource
ThreadID: b560fb90, access to resource
ThreadID: b5e10b90, wait for  resource
ThreadID: b560fb90, release   resource
ThreadID: b4e0eb90, access to resource
ThreadID: b560fb90, wait for  resource
ThreadID: b4e0eb90, release   resource
ThreadID: b7e14b90, access to resource
ThreadID: b4e0eb90, wait for  resource
ThreadID: b7e14b90, release   resource
ThreadID: b460db90, access to resource
ThreadID: b7e14b90, wait for  resource
ThreadID: b460db90, release   resource
ThreadID: b3e0cb90, access to resource
ThreadID: b460db90, wait for  resource
ThreadID: b3e0cb90, release   resource
ThreadID: b360bb90, access to resource
ThreadID: b3e0cb90, wait for  resource
ThreadID: b360bb90, release   resource
ThreadID: b7613b90, access to resource
ThreadID: b360bb90, wait for  resource
ThreadID: b7613b90, release   resource
ThreadID: b6e12b90, access to resource
ThreadID: b7613b90, wait for  resource
ThreadID: b6e12b90, release   resource
ThreadID: b6611b90, access to resource
ThreadID: b6e12b90, wait for  resource
ThreadID: b7e14b90, canceled
ThreadID: b7613b90, canceled
ThreadID: b6e12b90, canceled
ThreadID: b6611b90, canceled
ThreadID: b5e10b90, canceled
ThreadID: b560fb90, canceled
ThreadID: b4e0eb90, canceled
ThreadID: b460db90, canceled
ThreadID: b3e0cb90, canceled
ThreadID: b360bb90, canceled
after global_value: 13