/**
* @file util_thread.c
* スレッドを扱うモジュール。
*/
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <time.h>
#include "util_thread.h"
/* /////////////////////////////////////////////////////////////////////////////
//
// スレッド
//
*/
/* ============================================================================
* 構造体定義
* ============================================================================
*/
/**
* スレッドインスタンス構造体。
*/
struct thread {
void (*start_routine)(void*); /**< スレッドとして実行する関数 */
void* arg; /**< スレッドに渡すデータ */
pthread_t tid; /**< スレッドのID */
};
/* ============================================================================
* プロトタイプ宣言 (内部でのみ利用する関数)
* ============================================================================
*/
static void* thread_run(void* args);
/* ============================================================================
* 公開関数
* ============================================================================
*/
/**
* スレッドを生成します。
* スレッドの生成に失敗した場合、NULL を返します。
*
* @param start_routine スレッドで実行する関数
* @param arg スレッドに渡すデータへのポインタ
* @return スレッドインスタンス
*/
struct thread* thread_new(void (*start_routine)(void*), void* arg)
{
struct thread* thread = (struct thread*) malloc(sizeof(struct thread));
if (thread != NULL)
{
thread->start_routine = start_routine;
thread->arg = arg;
}
return thread;
}
/**
* スレッドインスタンスのリソースを開放します。
* スレッド自体が終了するわけではありません。
*
* @param thread スレッドインスタンス
*/
void thread_delete(struct thread* thread)
{
free(thread);
}
/**
* スレッドを開始します。
*
* @param thread スレッドインスタンス
*/
void thread_start(struct thread* thread)
{
pthread_create(&thread->tid, NULL, thread_run, thread);
}
/**
* 指定されたスレッドが終了するのを待ちます。
*
* @param thread スレッドインスタンス
*/
bool thread_join(struct thread* thread)
{
int ret = pthread_join(thread->tid, NULL);
return (ret == 0);
}
/**
* 現在のスレッドが指定されたスレッドと同一か否かを返します。
*
* @param thread スレッドインスタンス
* @return true/false (一致/不一致)
*/
bool thread_equals(struct thread* thread)
{
pthread_t tid = pthread_self();
return (tid == thread->tid);
}
/* ============================================================================
* 内部関数
* ============================================================================
*/
/**
* スレッドとして実行される関数。
* この関数の中で、スレッド起動に指定された関数を実行します。
*
* @param arg スレッドインスタンス
*/
static
void* thread_run(void* arg)
{
struct thread* thread = (struct thread*) arg;
thread->start_routine(thread->arg);
return NULL;
}
/* /////////////////////////////////////////////////////////////////////////////
//
// mutex
//
*/
/* ============================================================================
* 構造体定義
* ============================================================================
*/
/**
* mutex インスタンス構造体。
*/
struct mutex {
pthread_mutex_t mutex; /**< mutex オブジェクト */
};
/* ============================================================================
* 公開関数
* ============================================================================
*/
/**
* mutex を生成します。
* mutex の生成に失敗した場合、NULL を返します。
*
* @return mutex
*/
struct mutex* mutex_new(void)
{
struct mutex* mutex = (struct mutex*) malloc(sizeof(struct mutex));
if (mutex != NULL)
{
pthread_mutex_init(&mutex->mutex, NULL);
}
return mutex;
}
/**
* mutex を破棄します。
* mutex がロックされている場合は、破棄に失敗しエラーを返します。
*
* @param mutex 破棄する mutex
* @return true/false (破棄成功/破棄失敗 [mutex がロックされている])
*/
bool mutex_delete(struct mutex* mutex)
{
if (mutex != NULL)
{
int res = pthread_mutex_destroy(&mutex->mutex);
if (res == 0)
{
free(mutex);
return true;
}
}
return false;
}
/**
* mutex をロックします。
*
* @param mutex ロックする mutex
*/
void mutex_lock(struct mutex* mutex)
{
// mutex は、デフォルトの種別で初期化済みのため、
// EINVAL, EDEADLK のエラーは発生しない。
pthread_mutex_lock(&mutex->mutex);
}
/**
* mutex をアンロックします。
*
* @param mutex アンロックする mutex
*/
void mutex_unlock(struct mutex* mutex)
{
// mutex は、デフォルトの種別で初期化済みのため、
// EINVAL, EPERM のエラーは発生しない。
pthread_mutex_unlock(&mutex->mutex);
}
/* /////////////////////////////////////////////////////////////////////////////
//
// cond
//
*/
/* ============================================================================
* 構造体定義
* ============================================================================
*/
/**
* cond インスタンス構造体。
*/
struct cond {
pthread_cond_t cond; /**< cond オブジェクト */
};
/* ============================================================================
* 公開関数
* ============================================================================
*/
/**
* cond を生成します。
* cond の生成に失敗した場合、NULL を返します。
*
* @return cond
*/
struct cond* cond_new(void)
{
struct cond* cond = (struct cond*) malloc(sizeof(struct cond));
if (cond != NULL)
{
pthread_cond_init(&cond->cond, NULL);
}
return cond;
}
/**
* cond を破棄します。
* cond が条件変数を待っている場合、破棄に失敗しエラーを返します。
*
* @param cond 破棄する cond
* @return true/false (破棄成功/破棄失敗 [cond が条件変数を待っている])
*/
bool cond_delete(struct cond* cond)
{
if (cond!= NULL)
{
int res = pthread_cond_destroy(&cond->cond);
if (res == 0)
{
free(cond);
return true;
}
}
return false;
}
/**
* 指定された mutex のアンロックと、条件変数 cond の送信に対する待機を
* アトミックに行います。条件変数が送信されるまで、スレッドの実行は停止され、
* CPU時間を消費しません。
*
* 本関数を実行する前に、 mutex はロックされている必要があります。
* 本関数を呼び出しスレッドが、条件変数の待機完了により動作する際、
* mutex は再びロックされます。
*
* @param cond cond インスタンス
* @param mutex mutex ロック済みの mutex
*/
void cond_wait(struct cond* cond, struct mutex* mutex)
{
pthread_cond_wait(&cond->cond, &mutex->mutex);
}
/**
* 条件変数 cond に備えて待機しているスレッドの一つの実行を再開させます。
* cond を待機しているスレッドがなければ何もしません。
* 複数のスレッドが cond を待機している場合、どのスレッドが再開されるかはわからない。
*
* @param cond 再開させる cond
*/
void cond_signal(struct cond* cond)
{
pthread_cond_signal(&cond->cond);
}
/**
* 条件変数 cond に備えて待機しているすべてのスレッドを再開させます。
* cond を待機しているスレッドがなければ何もしません。
*
* @param cond 再開させる cond
*/
void cond_broadcast(struct cond* cond)
{
pthread_cond_broadcast(&cond->cond);
}