diff options
author | chai <chaifix@163.com> | 2019-08-02 20:51:00 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2019-08-02 20:51:00 +0800 |
commit | bad78945ceba425f6a80e3b8dca2414d592970eb (patch) | |
tree | 8bf7540766349c534bf9e5746b24fd7507ba034e /source/modules/asura-utils/Threads | |
parent | 99b90496765df21c5f377f42b9ed073ccb34c1fd (diff) |
*修改文件名格式
Diffstat (limited to 'source/modules/asura-utils/Threads')
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; + } + + } +} |