summaryrefslogtreecommitdiff
path: root/source/modules/asura-utils/Threads
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2019-08-02 20:51:00 +0800
committerchai <chaifix@163.com>2019-08-02 20:51:00 +0800
commitbad78945ceba425f6a80e3b8dca2414d592970eb (patch)
tree8bf7540766349c534bf9e5746b24fd7507ba034e /source/modules/asura-utils/Threads
parent99b90496765df21c5f377f42b9ed073ccb34c1fd (diff)
*修改文件名格式
Diffstat (limited to 'source/modules/asura-utils/Threads')
-rw-r--r--source/modules/asura-utils/Threads/Conditional.cpp84
-rw-r--r--source/modules/asura-utils/Threads/Conditional.h41
-rw-r--r--source/modules/asura-utils/Threads/Coroutine.cpp15
-rw-r--r--source/modules/asura-utils/Threads/Coroutine.h40
-rw-r--r--source/modules/asura-utils/Threads/Mutex.cpp105
-rw-r--r--source/modules/asura-utils/Threads/Mutex.h128
-rw-r--r--source/modules/asura-utils/Threads/Semaphore.cpp99
-rw-r--r--source/modules/asura-utils/Threads/Semaphore.h68
-rw-r--r--source/modules/asura-utils/Threads/Task.cpp10
-rw-r--r--source/modules/asura-utils/Threads/Task.h43
-rw-r--r--source/modules/asura-utils/Threads/Thread.cpp287
-rw-r--r--source/modules/asura-utils/Threads/Thread.h222
-rw-r--r--source/modules/asura-utils/Threads/ThreadImplPosix.cpp0
-rw-r--r--source/modules/asura-utils/Threads/ThreadImplPosix.h2
-rw-r--r--source/modules/asura-utils/Threads/ThreadImplSDL.cpp0
-rw-r--r--source/modules/asura-utils/Threads/ThreadImplSDL.h0
-rw-r--r--source/modules/asura-utils/Threads/ThreadImplStd.cpp0
-rw-r--r--source/modules/asura-utils/Threads/ThreadImplStd.h41
-rw-r--r--source/modules/asura-utils/Threads/ThreadImplWin32.cpp77
-rw-r--r--source/modules/asura-utils/Threads/ThreadImplWin32.h44
-rw-r--r--source/modules/asura-utils/Threads/Threadable.h23
-rw-r--r--source/modules/asura-utils/Threads/binding/_coroutine.cpp38
-rw-r--r--source/modules/asura-utils/Threads/binding/_thread.cpp208
23 files changed, 1575 insertions, 0 deletions
diff --git a/source/modules/asura-utils/Threads/Conditional.cpp b/source/modules/asura-utils/Threads/Conditional.cpp
new file mode 100644
index 0000000..f86a81e
--- /dev/null
+++ b/source/modules/asura-utils/Threads/Conditional.cpp
@@ -0,0 +1,84 @@
+#include "Conditional.h"
+
+namespace_begin(AsuraEngine)
+namespace_begin(Threads)
+
+Conditional::Conditional()
+ : m_Waiting(0)
+ , m_Signals(0)
+{
+}
+
+Conditional::~Conditional()
+{
+}
+
+void Conditional::Signal()
+{
+ m_Mutex.Lock();
+ if (m_Waiting > m_Signals)
+ {
+ ++m_Signals;
+ signal(m_WaitSem);
+ m_Mutex.Unlock();
+ wait(m_DoneSem);
+ }
+ else
+ {
+ m_Mutex.Unlock();
+ }
+}
+
+void Conditional::Broadcast()
+{
+ m_Mutex.Lock();
+ if (m_Waiting> m_Signals) {
+ int i, num_waiting;
+
+ num_waiting = (m_Waiting - m_Signals);
+ m_Signals = m_Waiting;
+ for (i = 0; i < num_waiting; ++i) {
+ signal(m_WaitSem);
+ }
+ m_Mutex.Unlock();
+ for (i = 0; i < num_waiting; ++i) {
+ wait(m_DoneSem);
+ }
+ }
+ else {
+ m_Mutex.Unlock();
+ }
+
+}
+
+bool Conditional::Wait(Mutex* mutex, int timeout /*= ASURA_MUTEX_MAXWAIT*/)
+{
+ bool retval;
+
+ m_Mutex.Lock();
+ ++m_Waiting;
+ m_Mutex.Unlock();
+
+ mutex->Unlock();
+
+ retval = wait(m_WaitSem, timeout);
+
+ m_Mutex.Lock();
+ if (m_Signals > 0) {
+ if (!retval) {
+ wait(m_WaitSem);
+ }
+ signal(m_DoneSem);
+
+ --m_Signals;
+ }
+ --m_Waiting;
+ m_Mutex.Unlock();
+
+ m_Mutex.Lock();
+
+ return retval;
+}
+
+namespace_end
+namespace_end \ No newline at end of file
diff --git a/source/modules/asura-utils/Threads/Conditional.h b/source/modules/asura-utils/Threads/Conditional.h
new file mode 100644
index 0000000..7a99ea1
--- /dev/null
+++ b/source/modules/asura-utils/Threads/Conditional.h
@@ -0,0 +1,41 @@
+#ifndef _ASURA_CONDITIONAL_H_
+#define _ASURA_CONDITIONAL_H_
+
+#include <asura-utils/Classes.h>
+
+#include "Mutex.h"
+#include "Semaphore.h"
+
+namespace_begin(AsuraEngine)
+namespace_begin(Threads)
+
+///
+///
+///
+class Conditional
+{
+public:
+
+ Conditional();
+ ~Conditional();
+
+ void Signal();
+ void Broadcast();
+ bool Wait(Mutex* mutex, int timeout = ASURA_MUTEX_MAXWAIT);
+
+private:
+
+ Mutex m_Mutex;
+
+ Semaphore m_WaitSem;
+ Semaphore m_DoneSem;
+
+ int m_Waiting;
+ int m_Signals;
+
+};
+
+namespace_end
+namespace_end
+
+#endif \ No newline at end of file
diff --git a/source/modules/asura-utils/Threads/Coroutine.cpp b/source/modules/asura-utils/Threads/Coroutine.cpp
new file mode 100644
index 0000000..5c4ab68
--- /dev/null
+++ b/source/modules/asura-utils/Threads/Coroutine.cpp
@@ -0,0 +1,15 @@
+#include "coroutine.h"
+
+namespace_begin(AsuraEngine)
+namespace_begin(Threads)
+
+/*
+Coroutine::Coroutine()
+{
+
+}
+*/
+
+
+namespace_end
+namespace_end
diff --git a/source/modules/asura-utils/Threads/Coroutine.h b/source/modules/asura-utils/Threads/Coroutine.h
new file mode 100644
index 0000000..cdb21f8
--- /dev/null
+++ b/source/modules/asura-utils/Threads/Coroutine.h
@@ -0,0 +1,40 @@
+#ifndef _ASURA_COROUTINE_H_
+#define _ASURA_COROUTINE_H_
+
+#include <asura-utils/Classes.h>
+
+#include "../Scripting/Portable.hpp"
+
+namespace_begin(AsuraEngine)
+namespace_begin(Threads)
+
+///
+/// luaЭ̣һЩ߼
+///
+class Coroutine ASURA_FINAL
+ : public AEScripting::Portable<Coroutine>
+{
+public:
+
+ LUAX_DECL_FACTORY(Coroutine);
+
+
+
+private:
+
+ ///
+ /// ǰЭ̵state
+ ///
+ lua_State* m_ThreadState;
+
+ LUAX_DECL_METHOD(_New);
+ LUAX_DECL_METHOD(_Run);
+
+};
+
+namespace_end
+namespace_end
+
+namespace AEThreading = AsuraEngine::Threads;
+
+#endif \ No newline at end of file
diff --git a/source/modules/asura-utils/Threads/Mutex.cpp b/source/modules/asura-utils/Threads/Mutex.cpp
new file mode 100644
index 0000000..501a0ed
--- /dev/null
+++ b/source/modules/asura-utils/Threads/Mutex.cpp
@@ -0,0 +1,105 @@
+#include <asura-utils/Exceptions/Exception.h>
+
+#include "Mutex.h"
+
+namespace_begin(AsuraEngine)
+namespace_begin(Threads)
+
+#define try_create_mutex(impl)\
+if (!m_Impl) \
+{ \
+try \
+{ \
+ m_Impl = new impl(); \
+} \
+catch (Exception& e) \
+{ \
+ m_Impl = nullptr; \
+} \
+}
+
+Mutex::Mutex()
+ : m_Impl(nullptr)
+{
+#if ASURA_MUTEX_WIN32_CRITICLE_SECTION
+ try_create_mutex(MutexImplWin32_CS);
+#endif
+#if ASURA_MUTEX_WIN32_KERNAL_MUTEX
+ try_create_mutex(MutexImplWin32_KM);
+#endif
+ ASSERT(m_Impl);
+}
+
+Mutex::~Mutex()
+{
+ if(m_Impl)
+ delete m_Impl;
+}
+
+void Mutex::Lock()
+{
+ ASSERT(m_Impl);
+
+ m_Impl->Lock();
+}
+
+void Mutex::Unlock()
+{
+ ASSERT(m_Impl);
+
+ m_Impl->Unlock();
+}
+
+#if ASURA_MUTEX_WIN32_CRITICLE_SECTION
+
+MutexImplWin32_CS::MutexImplWin32_CS()
+{
+ ::InitializeCriticalSection(&m_Mutex);
+}
+
+MutexImplWin32_CS::~MutexImplWin32_CS()
+{
+ ::DeleteCriticalSection(&m_Mutex);
+}
+
+void MutexImplWin32_CS::Lock()
+{
+ ::EnterCriticalSection(&m_Mutex);
+}
+
+void MutexImplWin32_CS::Unlock()
+{
+ ::LeaveCriticalSection(&m_Mutex);
+}
+
+#endif // ASURA_MUTEX_WIN32_CRITICLE_SECTION
+
+#if ASURA_MUTEX_WIN32_KERNAL_MUTEX
+
+MutexImplWin32_KM::MutexImplWin32_KM()
+{
+ m_Handle = ::CreateMutex(NULL, FALSE, NULL);
+ if (!m_Handle)
+ throw Exception("Cant use win32 mutex.");
+}
+
+MutexImplWin32_KM::~MutexImplWin32_KM()
+{
+ ::CloseHandle(m_Handle);
+ m_Handle = NULL;
+}
+
+void MutexImplWin32_KM::Lock()
+{
+ ::WaitForSingleObject(m_Handle, ASURA_MUTEX_MAXWAIT);
+}
+
+void MutexImplWin32_KM::Unlock()
+{
+ ::ReleaseMutex(m_Handle);
+}
+
+#endif // ASURA_MUTEX_WIN32_KERNAL_MUTEX
+
+namespace_end
+namespace_end \ No newline at end of file
diff --git a/source/modules/asura-utils/Threads/Mutex.h b/source/modules/asura-utils/Threads/Mutex.h
new file mode 100644
index 0000000..4269c05
--- /dev/null
+++ b/source/modules/asura-utils/Threads/Mutex.h
@@ -0,0 +1,128 @@
+#ifndef _ASURA_MUTEX_H_
+#define _ASURA_MUTEX_H_
+
+#include <asura-utils/Type.h>
+#include <asura-utils/Classes.h>
+
+#include "../UtilsConfig.h"
+
+#if ASURA_THREAD_WIN32
+#include <windows.h>
+#endif
+
+namespace_begin(AsuraEngine)
+namespace_begin(Threads)
+
+#define ASURA_MUTEX_MAXWAIT (~(uint32)0)
+
+class MutexImpl;
+
+class Mutex
+{
+public:
+
+ Mutex();
+ ~Mutex();
+
+ void Lock();
+ void Unlock();
+
+private:
+
+ // ֹ
+ Mutex(const Mutex&);
+ Mutex& operator=(const Mutex&);
+
+ MutexImpl* m_Impl;
+
+};
+
+class _mutex_locker
+{
+public:
+ _mutex_locker(Mutex& mutex)
+ : m(mutex)
+ {
+ m.Lock();
+ };
+ ~_mutex_locker()
+ {
+ m.Unlock();
+ }
+ operator bool() { return false; };
+private:
+ void* operator new(size_t);
+ Mutex& m;
+};
+
+#define lock(m) \
+if(_mutex_locker _asura_mutex_locker = m){} else
+
+ASURA_ABSTRACT class MutexImpl
+{
+public:
+
+ MutexImpl() {};
+ virtual ~MutexImpl() {};
+
+ virtual void Lock() = 0;
+ virtual void Unlock() = 0;
+
+};
+
+#if ASURA_MUTEX_WIN32_CRITICLE_SECTION
+
+//https://blog.csdn.net/l799623787/article/details/18259949
+class MutexImplWin32_CS ASURA_FINAL : public MutexImpl
+{
+public:
+
+ MutexImplWin32_CS();
+ ~MutexImplWin32_CS();
+
+ void Lock() override;
+ void Unlock() override;
+
+private:
+
+ //HANDLE m_Handle;
+ CRITICAL_SECTION m_Mutex;
+
+};
+
+#endif // ASURA_MUTEX_WIN32_CRITICLE_SECTION
+
+#if ASURA_MUTEX_WIN32_KERNAL_MUTEX
+
+class MutexImplWin32_KM ASURA_FINAL : public MutexImpl
+{
+public:
+
+ MutexImplWin32_KM();
+ ~MutexImplWin32_KM();
+
+ void Lock() override;
+ void Unlock() override;
+
+private:
+
+ HANDLE m_Handle;
+
+};
+
+#endif // ASURA_MUTEX_WIN32_KERNAL_MUTEX
+
+#if ASURA_THREAD_STD
+
+class MutexImplSTD ASURA_FINAL : public MutexImpl
+{
+};
+
+#endif // ASURA_THREAD_STD
+
+namespace_end
+namespace_end
+
+namespace AEThreading = AsuraEngine::Threads;
+
+#endif \ No newline at end of file
diff --git a/source/modules/asura-utils/Threads/Semaphore.cpp b/source/modules/asura-utils/Threads/Semaphore.cpp
new file mode 100644
index 0000000..a222f3d
--- /dev/null
+++ b/source/modules/asura-utils/Threads/Semaphore.cpp
@@ -0,0 +1,99 @@
+#include "../Exceptions/Exception.h"
+#include "../Type.h"
+
+#include "Mutex.h"
+#include "Semaphore.h"
+
+namespace_begin(AsuraEngine)
+namespace_begin(Threads)
+
+#define try_create_semaphore(impl) \
+if (!m_Impl) \
+{ \
+ try \
+ { \
+ m_Impl = new impl(init_count); \
+ } \
+ catch (Exception& e) \
+ { \
+ m_Impl = nullptr; \
+ } \
+}
+
+Semaphore::Semaphore(unsigned int init_count)
+ : m_Impl(nullptr)
+{
+#ifdef ASURA_THREAD_WIN32
+ try_create_semaphore(SemaphoreWin32);
+#endif
+ //ASSERT(m_Impl);
+}
+
+Semaphore::~Semaphore()
+{
+ if (m_Impl) delete m_Impl;
+}
+
+void Semaphore::Signal()
+{
+ ASSERT(m_Impl);
+ m_Impl->Signal();
+}
+
+bool Semaphore::Wait(int timeout /*= ASURA_MUTEX_MAXWAIT*/)
+{
+ ASSERT(m_Impl);
+ return m_Impl->Wait(timeout);
+}
+
+#if ASURA_THREAD_WIN32
+
+SemaphoreWin32::SemaphoreWin32(unsigned int init_value)
+ : SemaphoreImpl(init_value)
+{
+ // UINT_MAX get error.
+ m_Sem = CreateSemaphore(NULL, init_value, INT_MAX, NULL);
+ if (!m_Sem)
+ {
+ int errorCode = GetLastError();
+ throw Exception("Cant use win32 semaphore. Error code: %d.", errorCode);
+ }
+}
+
+SemaphoreWin32::~SemaphoreWin32()
+{
+ CloseHandle(m_Sem);
+}
+
+void SemaphoreWin32::Signal()
+{
+ InterlockedIncrement(&m_Count);
+ if (ReleaseSemaphore(m_Sem, 1, NULL) == FALSE)
+ InterlockedDecrement(&m_Count);
+}
+
+bool SemaphoreWin32::Wait(int timeout)
+{
+ int result;
+ result = WaitForSingleObject(m_Sem, timeout);
+ if (result == WAIT_OBJECT_0)
+ {
+ InterlockedDecrement(&m_Count);
+ return true;
+ }
+ else if(result == WAIT_TIMEOUT)
+ {
+ // ʱ
+ return false;
+ }
+ else
+ {
+ // δ֪
+ throw Exception("WaitForSingleObject() failed");
+ }
+}
+
+#endif // ASURA_THREAD_WIN32
+
+namespace_end
+namespace_end \ No newline at end of file
diff --git a/source/modules/asura-utils/Threads/Semaphore.h b/source/modules/asura-utils/Threads/Semaphore.h
new file mode 100644
index 0000000..41b1fd2
--- /dev/null
+++ b/source/modules/asura-utils/Threads/Semaphore.h
@@ -0,0 +1,68 @@
+#ifndef _ASURA_SEMAPHORE_H_
+#define _ASURA_SEMAPHORE_H_
+
+#include "../UtilsConfig.h"
+
+#if ASURA_THREAD_WIN32
+#include <windows.h>
+#endif
+
+namespace_begin(AsuraEngine)
+namespace_begin(Threads)
+
+class SemaphoreImpl;
+
+///
+/// ź
+///
+class Semaphore
+{
+public:
+
+ Semaphore(unsigned int init_count = 1);
+ ~Semaphore();
+
+ void Signal();
+ bool Wait(int timeout = ASURA_MUTEX_MAXWAIT);
+
+private:
+ SemaphoreImpl* m_Impl;
+};
+
+class SemaphoreImpl
+{
+public:
+ SemaphoreImpl(unsigned int init_value)
+ : m_Count(init_value)
+ {
+ };
+ virtual ~SemaphoreImpl() {};
+ virtual void Signal() = 0;
+ virtual bool Wait(int timeout) = 0;
+ inline int Current() { return m_Count; }
+protected:
+ unsigned int m_Count;
+};
+
+#define wait(sem, ...) sem.Wait(__VA_ARGS__)
+#define signal(sem) sem.Signal()
+
+#if ASURA_THREAD_WIN32
+
+class SemaphoreWin32 : public SemaphoreImpl
+{
+public:
+ SemaphoreWin32(unsigned int init_value);
+ ~SemaphoreWin32();
+ void Signal() override;
+ bool Wait(int timeout) override;
+private:
+ HANDLE m_Sem;
+};
+
+#endif // ASURA_THREAD_WIN32
+
+namespace_end
+namespace_end
+
+#endif \ No newline at end of file
diff --git a/source/modules/asura-utils/Threads/Task.cpp b/source/modules/asura-utils/Threads/Task.cpp
new file mode 100644
index 0000000..9666cc6
--- /dev/null
+++ b/source/modules/asura-utils/Threads/Task.cpp
@@ -0,0 +1,10 @@
+#include "task.h"
+#include "../scripting/Portable.hpp"
+
+using namespace AEScripting;
+
+namespace_begin(AsuraEngine)
+namespace_begin(Threads)
+
+namespace_end
+namespace_end
diff --git a/source/modules/asura-utils/Threads/Task.h b/source/modules/asura-utils/Threads/Task.h
new file mode 100644
index 0000000..b871303
--- /dev/null
+++ b/source/modules/asura-utils/Threads/Task.h
@@ -0,0 +1,43 @@
+#ifndef _ASURA_THRAD_TASK_H_
+#define _ASURA_THRAD_TASK_H_
+
+#include <asura-utils/Type.h>
+#include <asura-utils/Scripting/Portable.hpp>
+#include <asura-utils/Classes.h>
+
+namespace_begin(AsuraEngine)
+namespace_begin(Threads)
+
+///
+/// ϣһ̴߳񣬼̳TaskдExecute
+///
+ASURA_ABSTRACT class Task : public AEScripting::Object
+{
+public:
+
+ Task() {};
+ virtual ~Task() {};
+
+ ///
+ /// ִɺ󷵻trueûص
+ ///
+ virtual bool Execute() = 0;
+
+ ///
+ /// ûصinvoke threadص
+ ///
+ virtual void Invoke(lua_State* invokeThreaad) = 0;
+
+protected:
+
+ // ȡص
+ Luax::LuaxMemberRef m_Callback;
+
+};
+
+namespace_end
+namespace_end
+
+namespace AEThreading = AsuraEngine::Threads;
+
+#endif \ No newline at end of file
diff --git a/source/modules/asura-utils/Threads/Thread.cpp b/source/modules/asura-utils/Threads/Thread.cpp
new file mode 100644
index 0000000..1153912
--- /dev/null
+++ b/source/modules/asura-utils/Threads/Thread.cpp
@@ -0,0 +1,287 @@
+#include "Thread.h"
+
+#include "ThreadImplWin32.h"
+#include "ThreadImplPosix.h"
+#include "ThreadImplSdl.h"
+#include "ThreadImplStd.h"
+
+namespace_begin(AsuraEngine)
+namespace_begin(Threads)
+
+Thread::Thread(lua_State* luaThread, ThreadType type /*= THREAD_TYPE_DEFERRED*/, uint sleepTime /*= 0*/, const std::string& name /*= ""*/)
+ : m_Name(name)
+ , m_State(THREAD_STATE_IDLE)
+ , m_Type(type)
+ , m_LuaThread(luaThread)
+ , m_CallbackThread(nullptr)
+ , m_SleepTime(sleepTime)
+{
+ LUAX_STATE(luaThread);
+ if (type == THREAD_TYPE_IMMEDIATE)
+ {
+ Luax::LuaxVM* vm = state.GetVM();
+ ASSERT(vm);
+ m_CallbackThread = vm->CreateThread();
+ ASSERT(m_CallbackThread);
+ SetLuaxMemberRef(state, m_CallbackThreadRef, -1);
+ state.Pop(); // callback thread
+ }
+}
+
+Thread::~Thread()
+{
+ if (m_Impl)
+ {
+ delete m_Impl;
+ m_Impl = nullptr;
+ }
+}
+
+bool Thread::AddTask(Task* task)
+{
+ lock(m_TaskQueueMutex)
+ {
+ task->Retain();
+ m_TaskQueue.push(task);
+ }
+ return true;
+}
+
+uint Thread::GetTaskCount()
+{
+ return m_TaskQueue.size();
+}
+
+void Thread::Idle()
+{
+ m_State = THREAD_STATE_IDLE;
+}
+
+#define try_start_thread(impl)\
+if (!m_Impl) \
+{ \
+m_Impl = new impl(); \
+if (!m_Impl->Start(this, stacksize)) \
+{ \
+ delete m_Impl; \
+ m_Impl = nullptr; \
+} \
+}
+
+bool Thread::Start(bool isDaemon /*= true*/, uint32 stacksize /*= 0*/)
+{
+ if (m_State != THREAD_STATE_IDLE)
+ return false;
+
+ // Ѿһ֮ǰģر
+ if (m_Impl)
+ {
+ delete m_Impl;
+ m_Impl = nullptr;
+ }
+
+#if ASURA_THREAD_WIN32
+ try_start_thread(ThreadImplWin32);
+#endif
+
+ if (!m_Impl)
+ return false;
+
+ m_IsDaemon = isDaemon;
+ m_StateMutex.Lock();
+ m_State = THREAD_STATE_RUNNING;
+ m_StateMutex.Unlock();
+}
+
+void Thread::Pause()
+{
+ ASSERT(m_Impl);
+
+ lock(m_StateMutex)
+ {
+ m_State = THREAD_STATE_PAUSED;
+ }
+}
+
+void Thread::Resume()
+{
+ ASSERT(m_Impl);
+
+ lock(m_StateMutex)
+ {
+ if (m_State == THREAD_STATE_PAUSED)
+ m_State = THREAD_STATE_RUNNING;
+ }
+}
+
+void Thread::Stop()
+{
+ ASSERT(m_Impl);
+
+ lock(m_StateMutex)
+ {
+ m_State = THREAD_STATE_STOPPED;
+ }
+}
+
+void Thread::PauseSync()
+{
+ Pause();
+ wait(m_SemPause);
+}
+
+void Thread::ResumeSync()
+{
+ Resume();
+ wait(m_SemResume);
+}
+
+void Thread::StopSync()
+{
+ Stop();
+ wait(m_SemStop);
+}
+
+void Thread::Join()
+{
+ ASSERT(m_Impl);
+ m_Impl->Join();
+}
+
+ThreadState Thread::GetState()
+{
+ ThreadState state;
+ lock(m_StateMutex)
+ {
+ state = m_State;
+ }
+ return state;
+}
+
+bool Thread::IsRunning()
+{
+ ASSERT(m_Impl);
+
+ return GetState() == THREAD_STATE_RUNNING;
+}
+
+bool Thread::IsPaused()
+{
+ ASSERT(m_Impl);
+
+ return GetState() == THREAD_STATE_PAUSED;
+}
+
+bool Thread::IsStopped()
+{
+ ASSERT(m_Impl);
+
+ return GetState() == THREAD_STATE_STOPPED;
+}
+
+bool Thread::IsCurrent()
+{
+ ASSERT(m_Impl);
+
+ return m_Impl->IsCurrent();
+}
+
+const std::string& Thread::GetName()
+{
+ return m_Name;
+}
+
+int Thread::Process()
+{
+ LUAX_STATE(m_LuaThread);
+
+ do{
+ if (IsRunning())
+ {
+ while (!m_TaskQueue.empty())
+ {
+ Task* task = m_TaskQueue.front();
+ if (task && task->Execute())
+ {
+ if (m_Type == THREAD_TYPE_DEFERRED)
+ {
+ m_FinishedMutex.Lock();
+ task->Retain();
+ m_FinishedTasks.push(task);
+ m_FinishedMutex.Unlock();
+ }
+ else if (m_Type == THREAD_TYPE_IMMEDIATE)
+ {
+ // unsafe
+ task->Invoke(m_CallbackThread);
+ this->LuaxRelease<Task>(state, task);
+ }
+ m_TaskQueueMutex.Lock();
+ m_TaskQueue.pop();
+ task->Release();
+ m_TaskQueueMutex.Unlock();
+ }
+ }
+ }
+
+ // ˳ѭ
+ if (IsStopped())
+ break;
+
+ // CPUʹ
+ Sleep(m_SleepTime);
+
+ } while (m_IsDaemon);
+
+ // ػ̣߳еstop״̬
+ if (!m_IsDaemon)
+ Stop();
+
+ signal(m_SemStop);
+
+ // ״̬ΪIdle
+ Idle();
+
+ return 0;
+}
+
+///
+/// ӳģʽص
+///
+void Thread::Dispatch()
+{
+ if (m_Type != THREAD_TYPE_DEFERRED)
+ return;
+
+ LUAX_STATE(m_LuaThread);
+ while (!m_FinishedTasks.empty())
+ {
+ Task* task = m_FinishedTasks.front();
+ if (task)
+ {
+ task->Invoke(m_LuaThread);
+ this->LuaxRelease<Task>(state, task);
+ m_FinishedMutex.Lock();
+ m_FinishedTasks.pop();
+ task->Release();
+ m_FinishedMutex.Unlock();
+ }
+ }
+}
+
+void Thread::Sleep(uint ms)
+{
+ ASSERT(m_Impl);
+ if (m_Impl)
+ {
+ m_Impl->Sleep(ms);
+ }
+}
+
+void Thread::SetSleepTime(uint ms)
+{
+ m_SleepTime = ms;
+}
+
+namespace_end
+namespace_end \ No newline at end of file
diff --git a/source/modules/asura-utils/Threads/Thread.h b/source/modules/asura-utils/Threads/Thread.h
new file mode 100644
index 0000000..bc6f14e
--- /dev/null
+++ b/source/modules/asura-utils/Threads/Thread.h
@@ -0,0 +1,222 @@
+#ifndef _ASURA_THREAD_H_
+#define _ASURA_THREAD_H_
+
+#include <string>
+#include <queue>
+
+#include <asura-utils/Scripting/Portable.hpp>
+
+#include "Task.h"
+#include "Mutex.h"
+#include "Semaphore.h"
+#include "Threadable.h"
+
+namespace_begin(AsuraEngine)
+namespace_begin(Threads)
+
+class ThreadImpl;
+
+///
+/// ̵߳ļֲͬʵ֣
+/// 1: Deferredӳģʽ߳ϵɺҪ̵ֶ߳Dispatch
+/// ̵߳ص첽Ϊͬlua_Stateͻ⡣
+/// 2: Immediateģʽÿһ߳άһlua_newthreadlua_State
+/// صڲͬlua_Stateеãⲻ̷ͬ߳ͬһlua_State
+///
+enum ThreadType
+{
+ THREAD_TYPE_DEFERRED,
+ THREAD_TYPE_IMMEDIATE, // unsafe
+};
+
+enum ThreadState
+{
+ THREAD_STATE_IDLE, ///< ãδں˶
+ THREAD_STATE_RUNNING, ///< ѭ
+ THREAD_STATE_PAUSED, ///< ѭͣ
+ THREAD_STATE_STOPPED, ///< ˳ѭ
+};
+
+///
+/// ߳壬ÿ߳άһtask queue
+///
+class Thread ASURA_FINAL
+ : public AEScripting::Portable<Thread>
+ , public Threadable
+{
+public:
+
+ LUAX_DECL_FACTORY(Thread);
+
+ Thread(lua_State* luaThread, ThreadType type = THREAD_TYPE_DEFERRED, uint sleepTime = 1, const std::string& name = "");
+ ~Thread();
+
+ bool AddTask(Task* task);
+ ///
+ /// õȴ
+ ///
+ uint GetTaskCount();
+
+ void Idle();
+
+ ///
+ /// ں˶󣬲Сdaemonȴֶstopijʱ̶ɺԶstop
+ ///
+ bool Start(bool daemon = true, uint32 stacksize = 0);
+
+ ///
+ /// ͬ߳̿ƣʵʱġҪ߳ʹIsȷϵָ״̬
+ ///
+ void Pause();
+ void Resume();
+ void Stop();
+
+ ///
+ /// ͬ߳̿ƣȷźźִС̵߳ȴ
+ ///
+ void PauseSync();
+ void ResumeSync();
+ void StopSync();
+
+ ///
+ /// ̵߳ȴ߳̽żִС
+ ///
+ void Join();
+
+ ThreadState GetState();
+
+ ///
+ /// ߼߳״̬
+ /// 1: IdleУ̴߳Ĭ״̬ʱStart
+ /// 2: RunningУں˶´Ѿں˵УTask
+ /// 3: PausedͣȻںУ˶Ĵ߼ͣ
+ /// 4: StoppedֹͣȻںУѾ޷
+ ///
+ bool IsIdle();
+ bool IsRunning();
+ bool IsPaused();
+ bool IsStopped();
+
+ bool IsCurrent();
+
+ ///
+ /// ִС
+ ///
+ int Process() override;
+
+ const std::string& GetName();
+
+ ///
+ /// ص
+ ///
+ void Dispatch();
+
+ ///
+ /// ߺ
+ ///
+ void Sleep(uint ms);
+
+ ///
+ /// ʱ
+ ///
+ void SetSleepTime(uint ms);
+
+private:
+
+ //----------------------------------------------------------------------------//
+
+ LUAX_DECL_ENUM(ThreadType);
+ LUAX_DECL_ENUM(ThreadState);
+
+ LUAX_DECL_METHOD(_New);
+ LUAX_DECL_METHOD(_AddTask);
+ LUAX_DECL_METHOD(_Start);
+ LUAX_DECL_METHOD(_Idle);
+ LUAX_DECL_METHOD(_Pause);
+ LUAX_DECL_METHOD(_Resume);
+ LUAX_DECL_METHOD(_Stop);
+ LUAX_DECL_METHOD(_Join);
+ LUAX_DECL_METHOD(_IsRunning);
+ LUAX_DECL_METHOD(_IsPaused);
+ LUAX_DECL_METHOD(_IsStopped);
+ LUAX_DECL_METHOD(_IsCurrent);
+ LUAX_DECL_METHOD(_Sleep);
+ LUAX_DECL_METHOD(_Dispatch);
+ LUAX_DECL_METHOD(_GetName);
+ LUAX_DECL_METHOD(_GetType);
+ LUAX_DECL_METHOD(_GetState);
+ LUAX_DECL_METHOD(_SetSleepTime);
+
+ //----------------------------------------------------------------------------//
+
+ ThreadImpl* m_Impl;
+
+ lua_State* m_LuaThread;
+
+ ///
+ /// ˴Ƿػģʽ
+ ///
+ bool m_IsDaemon;
+
+ std::string m_Name;
+ ThreadType m_Type;
+ uint m_SleepTime;
+
+ ThreadState m_State;
+ Mutex m_StateMutex;
+
+ ///
+ /// ͬصź
+ ///
+ Semaphore m_SemPause;
+ Semaphore m_SemResume;
+ Semaphore m_SemStop;
+
+ ///
+ /// С
+ ///
+ std::queue<Task*> m_TaskQueue;
+ Mutex m_TaskQueueMutex;
+
+ ///
+ /// ӳģʽʹ
+ ///
+ std::queue<Task*> m_FinishedTasks;
+ Mutex m_FinishedMutex;
+
+ ///
+ /// ģʽʹãصʹõlua߳
+ ///
+ lua_State* m_CallbackThread;
+ Luax::LuaxMemberRef m_CallbackThreadRef;
+
+};
+
+///
+/// ̵߳ľʵ֣û͸ģһ׼ֲԣ
+/// 1: win32
+/// 2: posix
+/// 3: SDL
+/// 4: std::thread
+///
+ASURA_ABSTRACT class ThreadImpl
+{
+public:
+ ThreadImpl() {};
+ virtual ~ThreadImpl() {};
+
+ virtual bool Start(Threadable* thread, uint32 stacksize = 0) = 0;
+ virtual void Join() = 0;
+ virtual void Kill() = 0;
+
+ virtual void Sleep(uint ms) = 0;
+
+ virtual bool IsRunning() = 0;
+ virtual bool IsCurrent() = 0;
+
+};
+
+namespace_end
+namespace_end
+
+#endif \ No newline at end of file
diff --git a/source/modules/asura-utils/Threads/ThreadImplPosix.cpp b/source/modules/asura-utils/Threads/ThreadImplPosix.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/source/modules/asura-utils/Threads/ThreadImplPosix.cpp
diff --git a/source/modules/asura-utils/Threads/ThreadImplPosix.h b/source/modules/asura-utils/Threads/ThreadImplPosix.h
new file mode 100644
index 0000000..3089f0a
--- /dev/null
+++ b/source/modules/asura-utils/Threads/ThreadImplPosix.h
@@ -0,0 +1,2 @@
+#include <asura-utils/Classes.h>
+
diff --git a/source/modules/asura-utils/Threads/ThreadImplSDL.cpp b/source/modules/asura-utils/Threads/ThreadImplSDL.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/source/modules/asura-utils/Threads/ThreadImplSDL.cpp
diff --git a/source/modules/asura-utils/Threads/ThreadImplSDL.h b/source/modules/asura-utils/Threads/ThreadImplSDL.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/source/modules/asura-utils/Threads/ThreadImplSDL.h
diff --git a/source/modules/asura-utils/Threads/ThreadImplStd.cpp b/source/modules/asura-utils/Threads/ThreadImplStd.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/source/modules/asura-utils/Threads/ThreadImplStd.cpp
diff --git a/source/modules/asura-utils/Threads/ThreadImplStd.h b/source/modules/asura-utils/Threads/ThreadImplStd.h
new file mode 100644
index 0000000..452f569
--- /dev/null
+++ b/source/modules/asura-utils/Threads/ThreadImplStd.h
@@ -0,0 +1,41 @@
+#ifndef _ASURA_THREAD_STD_H_
+#define _ASURA_THREAD_STD_H_
+
+#include "../UtilsConfig.h"
+
+#if ASURA_THREAD_STD
+
+#include <windows.h>
+
+#include "Thread.h"
+
+namespace_begin(AsuraEngine)
+namespace_begin(Threads)
+
+///
+/// Threadstd::threadʵ֡
+///
+class ThreadImplSTD : public ThreadImpl
+{
+public:
+
+ ThreadImplSTD();
+ ~ThreadImplSTD();
+
+ bool Start(Threadable* thread, uint32 stacksize) override;
+ void Join() override;
+ void Kill() override;
+
+ bool IsRunning() override;
+ bool IsCurrent() override;
+
+private:
+
+};
+
+namespace_end
+namespace_end
+
+#endif // #if ASURA_THREAD_STD
+
+#endif // _ASURA_THREAD_STD_H_ \ No newline at end of file
diff --git a/source/modules/asura-utils/Threads/ThreadImplWin32.cpp b/source/modules/asura-utils/Threads/ThreadImplWin32.cpp
new file mode 100644
index 0000000..2467f87
--- /dev/null
+++ b/source/modules/asura-utils/Threads/ThreadImplWin32.cpp
@@ -0,0 +1,77 @@
+#include "ThreadImplWin32.h"
+#include "Thread.h"
+
+#include <iostream>
+
+#if ASURA_THREAD_WIN32
+
+namespace_begin(AsuraEngine)
+namespace_begin(Threads)
+
+static DWORD WINAPI _thread_win32_runner(LPVOID param)
+{
+ Threadable* thread = (Threadable*)param;
+ return thread->Process(); // β
+}
+
+ThreadImplWin32::ThreadImplWin32()
+{
+}
+
+ThreadImplWin32::~ThreadImplWin32()
+{
+ if (!m_Handle) return;
+ ::CloseHandle(m_Handle);
+ m_Handle = 0;
+}
+
+bool ThreadImplWin32::Start(Threadable* thread, uint32 stacksize/*=0*/)
+{
+ assert(!IsRunning());
+ m_Handle = ::CreateThread(
+ NULL
+ , stacksize
+ , _thread_win32_runner
+ , thread
+ , 0 /*е*/
+ , NULL);
+
+ return m_Handle;
+}
+
+void ThreadImplWin32::Join()
+{
+ // ̵߳ȴ̷߳
+ ::WaitForSingleObject(m_Handle, INFINITE);
+}
+
+void ThreadImplWin32::Kill()
+{
+ ::TerminateThread(m_Handle, FALSE);
+}
+
+void ThreadImplWin32::Sleep(uint ms)
+{
+ ::Sleep(ms);
+}
+
+bool ThreadImplWin32::IsRunning()
+{
+ if (m_Handle) {
+ DWORD exitCode = 0;
+ // https://blog.csdn.net/yuanmeng567/article/details/19485719
+ ::GetExitCodeThread(m_Handle, &exitCode);
+ return exitCode == STILL_ACTIVE;
+ }
+ return false;
+}
+
+bool ThreadImplWin32::IsCurrent()
+{
+ return m_Handle == ::GetCurrentThread();
+}
+
+namespace_end
+namespace_end
+
+#endif // ASURA_THREAD_WIN32 \ No newline at end of file
diff --git a/source/modules/asura-utils/Threads/ThreadImplWin32.h b/source/modules/asura-utils/Threads/ThreadImplWin32.h
new file mode 100644
index 0000000..93ca477
--- /dev/null
+++ b/source/modules/asura-utils/Threads/ThreadImplWin32.h
@@ -0,0 +1,44 @@
+#ifndef _ASURA_THREAD_WIN32_H__
+#define _ASURA_THREAD_WIN32_H__
+
+#include "../UtilsConfig.h"
+
+#if ASURA_THREAD_WIN32
+
+#include <windows.h>
+
+#include "thread.h"
+
+namespace_begin(AsuraEngine)
+namespace_begin(Threads)
+
+///
+/// Threadwin32ʵ֡
+///
+class ThreadImplWin32 : public ThreadImpl
+{
+public:
+
+ ThreadImplWin32();
+ ~ThreadImplWin32();
+
+ bool Start(Threadable* thread, uint32 stacksize) override;
+ void Join() override;
+ void Kill() override;
+
+ void Sleep(uint ms) override;
+
+ bool IsRunning() override;
+ bool IsCurrent() override;
+
+private:
+
+ HANDLE m_Handle;
+
+};
+
+namespace_end
+namespace_end
+
+#endif // #if ASURA_THREAD_WIN32
+#endif // _ASURA_THREAD_WIN32_H__ \ No newline at end of file
diff --git a/source/modules/asura-utils/Threads/Threadable.h b/source/modules/asura-utils/Threads/Threadable.h
new file mode 100644
index 0000000..fce7350
--- /dev/null
+++ b/source/modules/asura-utils/Threads/Threadable.h
@@ -0,0 +1,23 @@
+#ifndef _ASURA_THREADABLE_H_
+#define _ASURA_THREADABLE_H_
+
+#include "../Type.h"
+
+namespace_begin(AsuraEngine)
+namespace_begin(Threads)
+
+ASURA_ABSTRACT class Threadable
+{
+public:
+
+ Threadable() {};
+ virtual ~Threadable() {};
+
+ virtual int Process() = 0;
+
+};
+
+namespace_end
+namespace_end
+
+#endif \ No newline at end of file
diff --git a/source/modules/asura-utils/Threads/binding/_coroutine.cpp b/source/modules/asura-utils/Threads/binding/_coroutine.cpp
new file mode 100644
index 0000000..0656079
--- /dev/null
+++ b/source/modules/asura-utils/Threads/binding/_coroutine.cpp
@@ -0,0 +1,38 @@
+#include "../Coroutine.h"
+
+using namespace std;
+
+namespace_begin(AsuraEngine)
+namespace_begin(Threads)
+
+ LUAX_REGISTRY(Coroutine)
+ {
+ LUAX_REGISTER_METHODS(state,
+ { "New", _New },
+ { "Run", _Run }
+ );
+ }
+
+ LUAX_POSTPROCESS(Coroutine)
+ {
+
+ }
+
+ // Coroutine.New()
+ LUAX_IMPL_METHOD(Coroutine, _New)
+ {
+ LUAX_STATE(L);
+
+ return 0;
+ }
+
+ // coroutine:Run()
+ LUAX_IMPL_METHOD(Coroutine, _Run)
+ {
+ LUAX_PREPARE(L, Coroutine);
+
+ return 0;
+ }
+
+ }
+}
diff --git a/source/modules/asura-utils/Threads/binding/_thread.cpp b/source/modules/asura-utils/Threads/binding/_thread.cpp
new file mode 100644
index 0000000..aaa9e8d
--- /dev/null
+++ b/source/modules/asura-utils/Threads/binding/_thread.cpp
@@ -0,0 +1,208 @@
+#include "../Thread.h"
+
+using namespace std;
+
+namespace_begin(AsuraEngine)
+namespace_begin(Threads)
+
+ LUAX_REGISTRY(Thread)
+ {
+ LUAX_REGISTER_METHODS(state,
+ { "New", _New },
+ { "AddTask", _AddTask },
+ { "Start", _Start },
+ { "Idle", _Idle },
+ { "Pause", _Pause },
+ { "Resume", _Resume },
+ { "Stop", _Stop },
+ { "Join", _Join },
+ { "IsRunning", _IsRunning },
+ { "IsPaused", _IsPaused },
+ { "IsStopped", _IsStopped },
+ { "IsCurrent", _IsCurrent },
+ { "Sleep", _Sleep },
+ { "Dispatch", _Dispatch },
+ { "GetName", _GetName },
+ { "GetType", _GetType },
+ { "GetState", _GetState }
+ );
+ }
+
+ LUAX_POSTPROCESS(Thread)
+ {
+ LUAX_REGISTER_ENUM(state, "EThreadType",
+ { "DEFERRED", THREAD_TYPE_DEFERRED },
+ { "IMMEDIATE", THREAD_TYPE_IMMEDIATE }
+ );
+ LUAX_REGISTER_ENUM(state, "EThreadState",
+ { "IDLE", THREAD_STATE_IDLE },
+ { "RUNNING", THREAD_STATE_RUNNING },
+ { "PAUSED", THREAD_STATE_PAUSED },
+ { "STOPPED", THREAD_STATE_STOPPED }
+ );
+ }
+
+ // thread = Thread.New(thread_type, sleepTime, name)
+ LUAX_IMPL_METHOD(Thread, _New)
+ {
+ LUAX_STATE(L);
+
+ ThreadType type = (ThreadType)state.GetValue<int>(1, THREAD_TYPE_DEFERRED);
+ uint sleepTime = state.GetValue<uint>(2,1);
+ cc8* name = state.GetValue<cc8*>(3, "");
+
+ Thread* thread = new Thread(state, type, sleepTime, name);
+ thread->PushLuaxUserdata(state);
+
+ return 1;
+ }
+
+ // thread:AddTask(task)
+ LUAX_IMPL_METHOD(Thread, _AddTask)
+ {
+ LUAX_PREPARE(L, Thread);
+
+ Task* task = state.GetUserdata<Task>(2);
+ self->AddTask(task);
+ self->LuaxRetain<Task>(state, task);
+ return 0;
+ }
+
+ // successed = thread:Start(isDeamon, stackSize)
+ LUAX_IMPL_METHOD(Thread, _Start)
+ {
+ LUAX_PREPARE(L, Thread);
+
+ bool isDaemon = state.GetValue(2, true);
+ uint stackSize = state.GetValue(3, 0);
+
+ state.Push(self->Start(isDaemon, stackSize));
+ return 1;
+ }
+
+ // thread:Idle()
+ LUAX_IMPL_METHOD(Thread, _Idle)
+ {
+ LUAX_PREPARE(L, Thread);
+ self->Idle();
+ return 0;
+ }
+
+ // thread:Pause()
+ LUAX_IMPL_METHOD(Thread, _Pause)
+ {
+ LUAX_PREPARE(L, Thread);
+ self->Pause();
+ return 0;
+ }
+
+ // thread:Resume()
+ LUAX_IMPL_METHOD(Thread, _Resume)
+ {
+ LUAX_PREPARE(L, Thread);
+ self->Resume();
+ return 0;
+ }
+
+ // thread:Stop()
+ LUAX_IMPL_METHOD(Thread, _Stop)
+ {
+ LUAX_PREPARE(L, Thread);
+ self->Stop();
+ return 0;
+ }
+
+ // thread:Join()
+ LUAX_IMPL_METHOD(Thread, _Join)
+ {
+ LUAX_PREPARE(L, Thread);
+ self->Join();
+ return 0;
+ }
+
+ // thread:IsRunning()
+ LUAX_IMPL_METHOD(Thread, _IsRunning)
+ {
+ LUAX_PREPARE(L, Thread);
+ state.Push(self->IsRunning());
+ return 1;
+ }
+
+ // thread:IsPaused()
+ LUAX_IMPL_METHOD(Thread, _IsPaused)
+ {
+ LUAX_PREPARE(L, Thread);
+ state.Push(self->IsPaused());
+ return 1;
+ }
+
+ // thread:IsStopped()
+ LUAX_IMPL_METHOD(Thread, _IsStopped)
+ {
+ LUAX_PREPARE(L, Thread);
+ state.Push(self->IsStopped());
+ return 1;
+ }
+
+ // thread:IsCurrent()
+ LUAX_IMPL_METHOD(Thread, _IsCurrent)
+ {
+ LUAX_PREPARE(L, Thread);
+ state.Push(self->IsCurrent());
+ return 1;
+ }
+
+ // Thread.Sleep(ms)
+ LUAX_IMPL_METHOD(Thread, _Sleep)
+ {
+ LUAX_STATE(L);
+ uint ms = state.GetValue(1, 0);
+#ifdef _WIN32
+ ::Sleep(ms);
+#endif
+ return 0;
+ }
+
+ // thread:Dispatch()
+ LUAX_IMPL_METHOD(Thread, _Dispatch)
+ {
+ LUAX_PREPARE(L, Thread);
+ self->Dispatch();
+ return 0;
+ }
+
+ // thread:GetName()
+ LUAX_IMPL_METHOD(Thread, _GetName)
+ {
+ LUAX_PREPARE(L, Thread);
+ state.Push(self->GetName());
+ return 1;
+ }
+
+ // thread:GetType()
+ LUAX_IMPL_METHOD(Thread, _GetType)
+ {
+ LUAX_PREPARE(L, Thread);
+ state.Push(self->m_Type);
+ return 1;
+ }
+
+ // thread:GetState()
+ LUAX_IMPL_METHOD(Thread, _GetState)
+ {
+ LUAX_PREPARE(L, Thread);
+ state.Push(self->m_State);
+ return 1;
+ }
+
+ // thread:SetSleepTime(sleepTime)
+ LUAX_IMPL_METHOD(Thread, _SetSleepTime)
+ {
+ LUAX_PREPARE(L, Thread);
+ uint time = state.CheckValue<uint>(2);
+ self->SetSleepTime(time);
+ return 0;
+ }
+
+ }
+}