🌕

thread・mutexについての覚書

2022/05/05に公開

threadとは

「スレッド」は、複数の処理を平行して行う方法の一つ。

1つのプロセスで複数の処理を並行・並列で行うための仕組みで、メモリ空間は共有なので、変数を共有することが可能。

変数を共有する際に問題となるのが、複数同時に共有のデータへアクセスした時に不整合が発生すること。

その問題を解決するのに使用するのが「排他制御」と呼ばれる処理で、共有のデータに同時にアクセスしないようにする仕組みだ。

mutexとは

「ミューテックス」は「排他処理」と呼ばれる方法で、共有するデータへのアクセスを制御する。

pthread_create

現在のプロセスに新しい制御スレッドを追加する。

//プロトタイプ
int	pthread_create(pthread_t *tid, const pthread_attr_t *tattr, void*(*start_routine)(void *), void *arg); 

必要な状態動作を持つ tattr で pthread_create() 関数が呼び出される。

スレッドの生成で属性引数として NULL を使用するのは、デフォルト属性を使用するのと同じ効果がある。

どちらの場合もデフォルトのスレッドが生成される。

tattr は初期化されると、デフォルト動作を獲得。

start_routine は新しいスレッドで実行する関数。

start_routine が復帰すると、スレッドは終了状態を start_routine で戻される値に設定して終了する。

戻り値

正常終了時は 0 。

それ以外の戻り値はエラーが発生したことを示す。

pthread_detach

//プロトタイプ
int	pthread_detach(thread_t tid);

pthread_detach() 関数は、 tid が終了したときに、 tid によって消費されていたメモリ資源を即座に解放することを保証する。

しかしながら、これによって他のスレッドは pthread_join を用いて tid の終了に同期することができなくなる。

tid が終了していない場合、pthread_detach() によって、そのスレッドが終了することはない。

同じスレッドに対して複数の pthread_detach() 呼び出しが行われたときの効果は不定。

pthread_join()関数と比べると、「tid が終了するまで待たず」に、「tid が終了したときに tid によって消費されていたメモリ資源を解放することを保証」する。

戻り値
正常終了時は 0 。

それ以外の戻り値は、エラーが発生したことを示す。

pthread_join

//プロトタイプ
int	pthread_join(thread_t tid, void **status);

pthread_join() 関数は、指定したスレッドが終了するまで呼び出しスレッドをブロックする。

指定するスレッドは、現在のプロセス内のスレッドで、しかも切り離されていないものでなければない。

status が NULL でなければ、pthread_join() の正常終了時に status の指す記憶場所に終了したスレッドの終了状態が格納される。

複数のスレッドが、同じスレッドの終了を待つことはできない。

そのような状態が発生すると、あるスレッドは正常に戻るが、他のスレッドは ESRCH エラーを戻し失敗。

pthread_join() の復帰後は、そのスレッドに関連付けられていたスタック領域がそのアプリケーションで再利用できるようになる。

戻り値
正常終了時は 0 。

それ以外の戻り値は、エラーが発生したことを示す。

pthread_mutex_init

//プロトタイプ
int	pthread_mutexattr_init(pthread_mutexattr_t *mattr);

pthread_mutexattr_init()関数は、このオブジェクトに関連付けられた属性をデフォルト値に初期化する。

各属性オブジェクトのための記憶領域は、実行時にスレッドによって割り当てられる。

この関数が呼び出されたときの pshared 属性のデフォルト値は PTHREAD_PROCESS_PRIVATE で、初期化された mutex を 1 つのプロセスの中だけで使用できるという意味。

戻り値
正常終了時は 0 。

それ以外の戻り値は、エラーが発生したことを示す。

pthread_mutex_destroy

//プロトタイプ
int	pthread_mutexattr_destroy(pthread_mutexattr_t *mattr)

pthread_mutexattr_destroy()関数 は、pthread_mutexattr_init() によって生成された属性オブジェクトの管理に使用されていた記憶領域の割り当てを解除する。

戻り値
正常終了時は 0 。

それ以外の戻り値は、エラーが発生したことを示す。

pthread_mutex_lock

//プロトタイプ
int	pthread_mutex_lock(pthread_mutex_t *mutex);

pthread_mutex_lock()関数は、mutex が指す mutex をロックする。

pthread_mutex_lock() が戻ると、呼び出しスレッドが mutex をロックした状態になっている。

mutex が別のスレッドによってすでにロックされている (所有されている) 場合は、呼び出しスレッドは mutex が使用可能になるまでブロックされる 。

mutex 型が PTHREAD_MUTEX_NORMAL の場合、デッドロックの検出は行われない。

mutex をもう一度ロックしようとするとデッドロックが発生する。

スレッドが、ロックされていない mutex やロック解除された mutex をロック解除しようとした場合、引き起こされる動作は未定義。

mutex 型が PTHREAD_MUTEX_ERRORCHECK の場合、エラーチェックが提供される。

すでにロックされた mutex をもう一度ロックしようとすると、エラーが返される。

ロックされていない mutex やロック解除された mutex をロック解除しようとすると、エラーが返される。

mutex 型が PTHREAD_MUTEX_RECURSIVE の場合、mutex はロックの回数を記録する。

スレッドが最初に正常に mutex を獲得すると、ロック計数は 1 に設定される。

この mutex をスレッドがさらにロックするたびに、ロックカウントが 1 ずつ増える。

スレッドが mutex をロック解除するたびに、ロックカウントが 1 ずつ減る。

ロックカウントが 0 になると、その mutex を別のスレッドが獲得できるようになる。

ロックされていない mutex やロック解除された mutex をロック解除しようとすると、エラーが返される。

mutex 型が PTHREAD_MUTEX_DEFAULT の場合、繰り返し mutex をロックしようとすると、引き起こされる動作は未定義。

mutex をロックしていないスレッドがロック解除しようとした場合、引き起こされる動作は未定義。

また、ロックされていない mutex をロック解除しようとした場合、引き起こされる動作は未定義。

戻り値
正常終了時は 0 。

それ以外の戻り値は、エラーが発生したことを示す。

pthread_mutex_unlock

//プロトタイプ
int	pthread_mutex_unlock(pthread_mutex_t *mutex);

pthread_mutex_unlock() は、mutex が指す mutex のロックを解除する。

mutex を解放する方法は、mutex の 型属性に依存。

pthread_mutex_unlock() が呼び出されたときに、指定された mutex が指す mutex オブジェクトでブロックされているスレッドがあり、この呼び出しによって mutex が使用できるようになると、スケジューリング方針に基づいて mutex を獲得するスレッドが決定される。

PTHREAD_MUTEX_RECURSIVE のタイプの mutex の場合、mutex が使用可能になるのは、カウントが 0 になり、pthread_mutex_unlock() を呼び出したスレッドがこの mutex のロックを解除したとき。

戻り値
正常終了時は 0 。

それ以外の戻り値は、エラーが発生したことを示す。

Discussion