From 4ddb833deca2775f81b1891bfdeffc340a68f3fa Mon Sep 17 00:00:00 2001 From: Liu Date: Sun, 3 Feb 2019 13:09:07 +0800 Subject: [PATCH] fix(thread): LCUIThread_Join() has not waited for the thread to exit --- src/thread/win32/thread.c | 21 ++++- test/test_thread.c | 169 ++++++++++++++++++++------------------ 2 files changed, 105 insertions(+), 85 deletions(-) diff --git a/src/thread/win32/thread.c b/src/thread/win32/thread.c index dcf328cbf..9483c9c0a 100644 --- a/src/thread/win32/thread.c +++ b/src/thread/win32/thread.c @@ -55,6 +55,7 @@ static struct LCUIThreadModule { static unsigned __stdcall run_thread(void *arg) { LCUI_ThreadContext thread; + thread = (LCUI_ThreadContext)arg; thread->func(thread->arg); return 0; @@ -63,6 +64,7 @@ static unsigned __stdcall run_thread(void *arg) int LCUIThread_Create(LCUI_Thread *tid, void(*func)(void*), void *arg) { LCUI_ThreadContext ctx; + if (!self.active) { LinkedList_Init(&self.threads); LCUIMutex_Init(&self.mutex); @@ -93,6 +95,7 @@ static LCUI_ThreadContext LCUIThread_Find(LCUI_Thread tid) { LinkedListNode *node; LCUI_ThreadContext ctx; + for (LinkedList_Each(node, &self.threads)) { ctx = node->data; if (ctx && ctx->tid == tid) { @@ -105,6 +108,7 @@ static LCUI_ThreadContext LCUIThread_Find(LCUI_Thread tid) static LCUI_ThreadContext LCUIThread_Get(LCUI_Thread tid) { LCUI_ThreadContext ctx; + LCUIMutex_Lock(&self.mutex); ctx = LCUIThread_Find(tid); if (ctx) { @@ -130,6 +134,7 @@ void LCUIThread_Exit(void *retval) { LCUI_Thread tid; LCUI_ThreadContext ctx; + tid = LCUIThread_SelfID(); ctx = LCUIThread_Get(tid); if (!ctx) { @@ -148,6 +153,7 @@ void LCUIThread_Cancel(LCUI_Thread tid) abort(); #else LCUI_ThreadContext ctx; + ctx = LCUIThread_Get(tid); if (ctx) { TerminateThread(ctx->handle, 0); @@ -160,6 +166,7 @@ int LCUIThread_Join(LCUI_Thread thread, void **retval) { DWORD code; LCUI_ThreadContext ctx; + LCUIMutex_Lock(&self.mutex); ctx = LCUIThread_Find(thread); if (ctx == NULL) { @@ -168,9 +175,17 @@ int LCUIThread_Join(LCUI_Thread thread, void **retval) } ctx->has_waiter = TRUE; LCUIMutex_Unlock(&self.mutex); - if (!GetExitCodeThread(ctx->handle, &code)) { - WaitForSingleObject(ctx->handle, 5000); - } + do { + code = 0; + if (GetExitCodeThread(ctx->handle, &code) == 0) { + break; + } + if (code == STILL_ACTIVE) { + WaitForSingleObject(ctx->handle, 5000); + } else { + break; + } + } while (1); ctx = LCUIThread_Get(thread); if (ctx) { if (retval) { diff --git a/test/test_thread.c b/test/test_thread.c index 8aa175d43..50e643089 100644 --- a/test/test_thread.c +++ b/test/test_thread.c @@ -1,82 +1,87 @@ -#include -#include -#include -#include -#include -#include "test.h" - -typedef struct TestWorkerRec_ { - char data[32]; - int data_count; - LCUI_BOOL active; - LCUI_Cond cond; - LCUI_Mutex mutex; - LCUI_Thread thread; -} TestWorkerRec, *TestWorker; - -static void TestWorker_Thread( void *arg ) -{ - TestWorker worker = arg; - - worker->active = TRUE; - worker->data_count = 0; - LCUIMutex_Lock( &worker->mutex ); - while( worker->active ) { - TEST_LOG( "waiting...\n" ); - LCUICond_Wait( &worker->cond, &worker->mutex ); - TEST_LOG( "get data: %s\n", worker->data ); - worker->data_count += 1; - } - LCUIMutex_Unlock( &worker->mutex ); - TEST_LOG( "count: %lu\n", worker->data_count ); -} - -static void TestWorker_Send( TestWorker worker, const char *data ) -{ - LCUIMutex_Lock( &worker->mutex ); - strcpy( worker->data, data ); - LCUICond_Signal( &worker->cond ); - LCUIMutex_Unlock( &worker->mutex ); -} - -static void TestWorker_Init( TestWorker worker ) -{ - LCUIMutex_Init( &worker->mutex ); - LCUICond_Init( &worker->cond ); -} - -static void TestWorker_Destroy( TestWorker worker ) -{ - LCUIMutex_Lock( &worker->mutex ); - worker->active = FALSE; - LCUICond_Signal( &worker->cond ); - LCUIMutex_Unlock( &worker->mutex ); - LCUIThread_Join( worker->thread, NULL ); - LCUIMutex_Destroy( &worker->mutex ); - LCUICond_Destroy( &worker->cond ); -} - -int test_thread( void ) -{ - int ret = 0; - TestWorkerRec worker; - - TestWorker_Init( &worker ); - LCUIThread_Create( &worker.thread, TestWorker_Thread, &worker ); - LCUI_Sleep( 1 ); - TestWorker_Send( &worker, "hello" ); - LCUI_MSleep( 200 ); - TestWorker_Send( &worker, "world" ); - LCUI_Sleep( 1 ); - TestWorker_Send( &worker, "this" ); - LCUI_MSleep( 500 ); - TestWorker_Send( &worker, "is" ); - LCUI_Sleep( 1 ); - TestWorker_Send( &worker, "test" ); - LCUI_MSleep( 100 ); - TestWorker_Send( &worker, "bye!" ); - LCUI_Sleep( 1 ); - TestWorker_Destroy( &worker ); - CHECK( worker.data_count == 7 ); - return ret; -} +#include +#include +#include +#include +#include +#include "test.h" + +typedef struct TestWorkerRec_ { + char data[32]; + int data_count; + LCUI_BOOL cancel; + LCUI_BOOL active; + LCUI_Cond cond; + LCUI_Mutex mutex; + LCUI_Thread thread; +} TestWorkerRec, *TestWorker; + +static void TestWorker_Thread(void *arg) +{ + TestWorker worker = arg; + + worker->cancel = FALSE; + worker->active = TRUE; + worker->data_count = 0; + LCUIMutex_Lock(&worker->mutex); + while (!worker->cancel && worker->data_count < 20) { + TEST_LOG("waiting...\n"); + LCUICond_Wait(&worker->cond, &worker->mutex); + TEST_LOG("get data: %s\n", worker->data); + worker->data_count += 1; + } + LCUIMutex_Unlock(&worker->mutex); + TEST_LOG("count: %lu\n", worker->data_count); + worker->active = FALSE; + LCUIThread_Exit(NULL); +} + +static void TestWorker_Send(TestWorker worker, const char *data) +{ + LCUIMutex_Lock(&worker->mutex); + strcpy(worker->data, data); + LCUICond_Signal(&worker->cond); + LCUIMutex_Unlock(&worker->mutex); +} + +static void TestWorker_Init(TestWorker worker) +{ + LCUIMutex_Init(&worker->mutex); + LCUICond_Init(&worker->cond); +} + +static void TestWorker_Destroy(TestWorker worker) +{ + LCUIMutex_Lock(&worker->mutex); + worker->cancel = TRUE; + LCUICond_Signal(&worker->cond); + LCUIMutex_Unlock(&worker->mutex); + LCUIThread_Join(worker->thread, NULL); + LCUIMutex_Destroy(&worker->mutex); + LCUICond_Destroy(&worker->cond); +} + +int test_thread(void) +{ + int ret = 0; + TestWorkerRec worker; + + TestWorker_Init(&worker); + LCUIThread_Create(&worker.thread, TestWorker_Thread, &worker); + LCUI_Sleep(1); + TestWorker_Send(&worker, "hello"); + LCUI_MSleep(200); + TestWorker_Send(&worker, "world"); + LCUI_Sleep(1); + TestWorker_Send(&worker, "this"); + LCUI_MSleep(500); + TestWorker_Send(&worker, "is"); + LCUI_Sleep(1); + TestWorker_Send(&worker, "test"); + LCUI_MSleep(100); + TestWorker_Send(&worker, "bye!"); + LCUI_Sleep(1); + TestWorker_Destroy(&worker); + CHECK(worker.data_count == 7); + CHECK(!worker.active); + return ret; +}