Skip to content

Commit

Permalink
fix(thread): LCUIThread_Join() has not waited for the thread to exit
Browse files Browse the repository at this point in the history
  • Loading branch information
lc-soft committed Mar 4, 2019
1 parent 93f3d77 commit 4ddb833
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 85 deletions.
21 changes: 18 additions & 3 deletions src/thread/win32/thread.c
Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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) {
Expand All @@ -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) {
Expand All @@ -130,6 +134,7 @@ void LCUIThread_Exit(void *retval)
{
LCUI_Thread tid;
LCUI_ThreadContext ctx;

tid = LCUIThread_SelfID();
ctx = LCUIThread_Get(tid);
if (!ctx) {
Expand All @@ -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);
Expand All @@ -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) {
Expand All @@ -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) {
Expand Down
169 changes: 87 additions & 82 deletions test/test_thread.c
@@ -1,82 +1,87 @@
#include <string.h>
#include <stdio.h>
#include <LCUI_Build.h>
#include <LCUI/LCUI.h>
#include <LCUI/thread.h>
#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 <string.h>
#include <stdio.h>
#include <LCUI_Build.h>
#include <LCUI/LCUI.h>
#include <LCUI/thread.h>
#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;
}

0 comments on commit 4ddb833

Please sign in to comment.