/** * @file kc_thread.c * @brief スレッドモジュール * @copyright 2020 - 2024 Nomura Kei */ #include <stdio.h> #include <kc_threads.h> #include <kc_threads_win.h> #if (KC_IS_WINDOWS) int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) { if ((thr == NULL) || (func == NULL)) { return thrd_error; } thr->handle = CreateThread( NULL, // セキュリティ属性 0, // スタックサイズ (LPTHREAD_START_ROUTINE)func, // スレッド関数 arg, // 引数 0, // 作成フラグ &(thr->thread_id) // スレッドID ); if (thr->handle == NULL) { return thrd_error; } return thrd_success; } int thrd_join(thrd_t thr, int *res) { if (WaitForSingleObject(thr.handle, INFINITE) != WAIT_OBJECT_0) { return thrd_error; } if (res != NULL) { DWORD retcode; if (GetExitCodeThread(thr.handle, &retcode) == 0) { return thrd_error; } *res = (int)retcode; } CloseHandle(thr.handle); return thrd_success; } int thrd_detach(thrd_t thr) { if (thr.handle == NULL) { return thrd_error; } if (CloseHandle(thr.handle) == 0) { return thrd_error; } return thrd_success; } thrd_t thrd_current(void) { thrd_t current; current.handle = GetCurrentThread(); current.thread_id = GetThreadId(current.handle); return current; } int thrd_equal(thrd_t lhs, thrd_t rhs) { return (lhs.thread_id == rhs.thread_id); } void thrd_yield(void) { SwitchToThread(); } int thrd_sleep(const struct timespec *duration, struct timespec *remaining) { if (duration == NULL) { return thrd_error; } // Windows の Sleep は、ms 単位 DWORD msec = (DWORD)(duration->tv_sec * 1000 + duration->tv_nsec / 1000000); Sleep(msec); // 常に成功したものとして、remaining は 0 に設定する。 if (remaining != NULL) { remaining->tv_sec = 0; remaining->tv_nsec = 0; } return thrd_success; } /** * 指定されたミューテックスを初期化します。 * Windows の場合、常に mtx_recursive が有効となります。 * * @param mtx 初期化するミューテックスの識別子 * @param type タイプ (mtx_plain, mtx_timed, mtx_plain|mtx_recursive, mtx_timed|mtx_recursive) * @return thrd_success/thrd_error (成功/失敗) */ int mtx_init(mtx_t *mtx, int type) { if (mtx == NULL) { return thrd_error; } mtx->type = type; InitializeCriticalSection(&mtx->cs); return thrd_success; } /** * ミューテックスを破棄します。 * * @param mtx 破棄するミューテックス識別子 */ void mtx_destroy(mtx_t *mtx) { printf("mtx_destroy: mtx->cs:%p\n", &mtx->cs); DeleteCriticalSection(&mtx->cs); } /** * 指定されたミューテックスがロックされるまで現在のスレッドをロックします。 * * @param mtx ミューテックス識別子 * @return thrd_success/thrd_error (成功/失敗) */ int mtx_lock(mtx_t *mtx) { EnterCriticalSection(&mtx->cs); return thrd_success; } /** * */ int mtx_unlock(mtx_t *mtx) { LeaveCriticalSection(&mtx->cs); return thrd_success; } int cnd_init(cnd_t *cond) { if (cond == NULL) { return thrd_error; } InitializeConditionVariable(&cond->cond); return thrd_success; } int cnd_signal(cnd_t *cond) { if (cond == NULL) { return thrd_error; } WakeConditionVariable(&cond->cond); return thrd_success; } int cnd_broadcast(cnd_t *cond) { if (cond == NULL) { return thrd_error; } WakeAllConditionVariable(&cond->cond); return thrd_success; } int cnd_wait(cnd_t *cond, mtx_t *mtx) { if ((cond == NULL) || (mtx == NULL)) { return thrd_error; } if (SleepConditionVariableCS(&cond->cond, &mtx->cs, INFINITE)) { return thrd_success; } return thrd_error; } int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) { if ((cond == NULL) || (mtx == NULL) || (ts == NULL)) { return thrd_error; } DWORD msec = (DWORD)(ts->tv_sec * 1000 + ts->tv_nsec / 1000000); if (SleepConditionVariableCS(&cond->cond, &mtx->cs, msec)) { return thrd_timedout; } return thrd_error; } void cnd_destroy(cnd_t *cond) { // Nothing to do UNUSED_VARIABLE(cond); } #endif