Newer
Older
bashrc / .bash.d / tmp / util / src / util_thread.c
Nomura.Kei on 24 Jan 2020 7 KB UPDATE
/**
 * @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);
}