diff options
Diffstat (limited to 'source/libs/asura-lib-utils/threading')
22 files changed, 1465 insertions, 0 deletions
diff --git a/source/libs/asura-lib-utils/threading/binding/_coroutine.cpp b/source/libs/asura-lib-utils/threading/binding/_coroutine.cpp new file mode 100644 index 0000000..7f74cca --- /dev/null +++ b/source/libs/asura-lib-utils/threading/binding/_coroutine.cpp @@ -0,0 +1,40 @@ +#include "../coroutine.h" + +using namespace std; + +namespace AsuraEngine +{ + namespace Threading + { + + 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/libs/asura-lib-utils/threading/binding/_thread.cpp b/source/libs/asura-lib-utils/threading/binding/_thread.cpp new file mode 100644 index 0000000..a5aff03 --- /dev/null +++ b/source/libs/asura-lib-utils/threading/binding/_thread.cpp @@ -0,0 +1,210 @@ +#include "../thread.h" + +using namespace std; + +namespace AsuraEngine +{ + namespace Threading + { + + 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 }, + { "Post", _Post }, + { "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", + { "READY", 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:Post() + LUAX_IMPL_METHOD(Thread, _Post) + { + LUAX_PREPARE(L, Thread); + self->Post(); + 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->mType); + return 1; + } + + // thread:GetState() + LUAX_IMPL_METHOD(Thread, _GetState) + { + LUAX_PREPARE(L, Thread); + state.Push(self->mState); + 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; + } + + } +} diff --git a/source/libs/asura-lib-utils/threading/coroutine.cpp b/source/libs/asura-lib-utils/threading/coroutine.cpp new file mode 100644 index 0000000..9f65c5f --- /dev/null +++ b/source/libs/asura-lib-utils/threading/coroutine.cpp @@ -0,0 +1,16 @@ +#include "coroutine.h" + +namespace AsuraEngine +{ + namespace Threading + { +/* + Coroutine::Coroutine() + { + + } +*/ + + + } +} diff --git a/source/libs/asura-lib-utils/threading/coroutine.h b/source/libs/asura-lib-utils/threading/coroutine.h new file mode 100644 index 0000000..01af654 --- /dev/null +++ b/source/libs/asura-lib-utils/threading/coroutine.h @@ -0,0 +1,40 @@ +#ifndef __ASURA_COROUTINE_H__ +#define __ASURA_COROUTINE_H__ + +#include "../scripting/portable.hpp" + +namespace AsuraEngine +{ + namespace Threading + { + + /// + /// luaЭ̣һЩ + /// + class Coroutine ASURA_FINAL + : public AEScripting::Portable<Coroutine> + { + public: + + LUAX_DECL_FACTORY(Coroutine); + + + + private: + + /// + /// ǰЭ̵state + /// + lua_State* mThreadState; + + LUAX_DECL_METHOD(_New); + LUAX_DECL_METHOD(_Run); + + }; + + } +} + +namespace AEThreading = AsuraEngine::Threading; + +#endif
\ No newline at end of file diff --git a/source/libs/asura-lib-utils/threading/mutex.cpp b/source/libs/asura-lib-utils/threading/mutex.cpp new file mode 100644 index 0000000..663ac28 --- /dev/null +++ b/source/libs/asura-lib-utils/threading/mutex.cpp @@ -0,0 +1,106 @@ +#include <asura-lib-utils/exceptions/exception.h> + +#include "mutex.h" + +namespace AsuraEngine +{ + namespace Threading + { + +#define try_create_mutex(impl)\ + if (!mImpl) \ + { \ + try \ + { \ + mImpl = new impl(); \ + } \ + catch (Exception& e) \ + { \ + mImpl = nullptr; \ + } \ + } + + Mutex::Mutex() + : mImpl(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(mImpl); + } + + Mutex::~Mutex() + { + delete mImpl; + } + + void Mutex::Lock() + { + ASSERT(mImpl); + + mImpl->Lock(); + } + + void Mutex::Unlock() + { + ASSERT(mImpl); + + mImpl->Unlock(); + } + +#if ASURA_MUTEX_WIN32_CRITICLE_SECTION + + MutexImplWin32_CS::MutexImplWin32_CS() + { + ::InitializeCriticalSection(&mMutex); + } + + MutexImplWin32_CS::~MutexImplWin32_CS() + { + ::DeleteCriticalSection(&mMutex); + } + + void MutexImplWin32_CS::Lock() + { + ::EnterCriticalSection(&mMutex); + } + + void MutexImplWin32_CS::Unlock() + { + ::LeaveCriticalSection(&mMutex); + } + +#endif // ASURA_MUTEX_WIN32_CRITICLE_SECTION + +#if ASURA_MUTEX_WIN32_KERNAL_MUTEX + + MutexImplWin32_KM::MutexImplWin32_KM() + { + mHandle = ::CreateMutex(NULL, FALSE, NULL); + if (!mHandle) + throw Exception("Cant use win32 mutex."); + } + + MutexImplWin32_KM::~MutexImplWin32_KM() + { + ::CloseHandle(mHandle); + mHandle = NULL; + } + + void MutexImplWin32_KM::Lock() + { + ::WaitForSingleObject(mHandle, INFINITE); + } + + void MutexImplWin32_KM::Unlock() + { + ::ReleaseMutex(mHandle); + } + +#endif // ASURA_MUTEX_WIN32_KERNAL_MUTEX + + } +} diff --git a/source/libs/asura-lib-utils/threading/mutex.h b/source/libs/asura-lib-utils/threading/mutex.h new file mode 100644 index 0000000..7e7d877 --- /dev/null +++ b/source/libs/asura-lib-utils/threading/mutex.h @@ -0,0 +1,126 @@ +#ifndef __ASURA_MUTEX_H__ +#define __ASURA_MUTEX_H__ + +#include <asura-lib-utils/type.h> + +#include "../utils_config.h" + +#if ASURA_THREAD_WIN32 + #include <windows.h> +#endif + +namespace AsuraEngine +{ + namespace Threading + { + + class MutexImpl; + + class Mutex + { + public: + + Mutex(); + ~Mutex(); + + void Lock(); + void Unlock(); + + private: + + MutexImpl* mImpl; + + }; + + class _mutex_locker + { + public: + _mutex_locker(Mutex& mutex) + : m(mutex) + { + m.Lock(); + }; + ~_mutex_locker() + { + m.Unlock(); + } + private: + void* operator new(size_t); + Mutex& m; + }; + +// ڵջӴλÿʼջΪٽ +#define lock(mutex) _mutex_locker _asura_scoped_lock_0x0(mutex) +#define lock2(mutex) _mutex_locker _asura_scoped_lock_0x1(mutex) +#define lock3(mutex) _mutex_locker _asura_scoped_lock_0x2(mutex) +#define lock4(mutex) _mutex_locker _asura_scoped_lock_0x3(mutex) +#define lock5(mutex) _mutex_locker _asura_scoped_lock_0x4(mutex) + + 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 mHandle; + CRITICAL_SECTION mMutex; + + }; + +#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 mHandle; + + }; + +#endif // ASURA_MUTEX_WIN32_KERNAL_MUTEX + +#if ASURA_THREAD_STD + + class MutexImplSTD ASURA_FINAL : public MutexImpl + { + }; + +#endif // ASURA_THREAD_STD + + } +} + +namespace AEThreading = AsuraEngine::Threading; + +#endif
\ No newline at end of file diff --git a/source/libs/asura-lib-utils/threading/semaphore.cpp b/source/libs/asura-lib-utils/threading/semaphore.cpp new file mode 100644 index 0000000..d59ec78 --- /dev/null +++ b/source/libs/asura-lib-utils/threading/semaphore.cpp @@ -0,0 +1,88 @@ +#include "../exceptions/exception.h" +#include "../type.h" + +#include "semaphore.h" + +namespace AsuraEngine +{ + namespace Threading + { + +#define try_create_semaphore(impl) \ + if (!mImpl) \ + { \ + try \ + { \ + mImpl = new impl(init_count); \ + } \ + catch (Exception& e) \ + { \ + mImpl = nullptr; \ + } \ + } + + Semaphore::Semaphore(unsigned int init_count) + : mImpl(nullptr) + { +#ifdef ASURA_THREAD_WIN32 + try_create_semaphore(SemaphoreWin32); +#endif + ASSERT(mImpl); + } + + Semaphore::~Semaphore() + { + if (mImpl) delete mImpl; + } + + void Semaphore::Signal() + { + ASSERT(mImpl); + mImpl->Signal(); + } + + void Semaphore::Wait(int timeout) + { + ASSERT(mImpl); + mImpl->Wait(timeout); + } + +#if ASURA_THREAD_WIN32 + + SemaphoreWin32::SemaphoreWin32(unsigned int init_value) + : SemaphoreImpl(init_value) + { + mSem = CreateSemaphore(NULL, init_value, UINT_MAX, NULL); + if (!mSem) + throw Exception("Cant use win32 semaphore."); + } + + SemaphoreWin32::~SemaphoreWin32() + { + CloseHandle(mSem); + } + + void SemaphoreWin32::Signal() + { + InterlockedIncrement(&mCount); + if (ReleaseSemaphore(mSem, 1, NULL) == FALSE) + InterlockedDecrement(&mCount); + } + + bool SemaphoreWin32::Wait(int timeout) + { + int result; + result = WaitForSingleObject(mSem, timeout < 0 ? INFINITE : timeout); + if (result == WAIT_OBJECT_0) + { + InterlockedDecrement(&mCount); + return true; + } + else + return false; + } + +#endif // ASURA_THREAD_WIN32 + + } +}
\ No newline at end of file diff --git a/source/libs/asura-lib-utils/threading/semaphore.h b/source/libs/asura-lib-utils/threading/semaphore.h new file mode 100644 index 0000000..80773d8 --- /dev/null +++ b/source/libs/asura-lib-utils/threading/semaphore.h @@ -0,0 +1,70 @@ +#ifndef __ASURA_SEMAPHORE_H__ +#define __ASURA_SEMAPHORE_H__ + +#include "../utils_config.h" + +#if ASURA_THREAD_WIN32 +#include <windows.h> +#endif + +namespace AsuraEngine +{ + namespace Threading + { + + class SemaphoreImpl; + + /// + /// ź + /// + class Semaphore + { + public: + + Semaphore(unsigned int init_count = 1); + ~Semaphore(); + + void Signal(); + void Wait(int timeout = 0); + + private: + SemaphoreImpl* mImpl; + }; + + class SemaphoreImpl + { + public: + SemaphoreImpl(unsigned int init_value) + : mCount(init_value) + { + }; + virtual ~SemaphoreImpl() {}; + virtual void Signal() = 0; + virtual bool Wait(int timeout) = 0; + inline int Current() { return mCount; } + protected: + unsigned int mCount; + }; + +#define wait(sem) sem.Wait(); +#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 mSem; + }; + +#endif // ASURA_THREAD_WIN32 + + } +} + +#endif
\ No newline at end of file diff --git a/source/libs/asura-lib-utils/threading/task.cpp b/source/libs/asura-lib-utils/threading/task.cpp new file mode 100644 index 0000000..2e84ed4 --- /dev/null +++ b/source/libs/asura-lib-utils/threading/task.cpp @@ -0,0 +1,12 @@ +#include "task.h" +#include "../scripting/lua_env.h" + +using namespace AEScripting; + +namespace AsuraEngine +{ + namespace Threading + { + + } +} diff --git a/source/libs/asura-lib-utils/threading/task.h b/source/libs/asura-lib-utils/threading/task.h new file mode 100644 index 0000000..fb7aa5f --- /dev/null +++ b/source/libs/asura-lib-utils/threading/task.h @@ -0,0 +1,45 @@ +#ifndef __ASURA_THRAD_TASK_H__ +#define __ASURA_THRAD_TASK_H__ + +#include <asura-lib-utils/type.h> +#include <asura-lib-utils/scripting/portable.hpp> + +namespace AsuraEngine +{ + namespace Threading + { + + /// + /// ϣһ̴̳߳TaskдExecute + /// + ASURA_ABSTRACT class Task + : public virtual AEScripting::NativeAccessor + { + public: + + Task() {}; + virtual ~Task() {}; + + /// + /// ִɺtrueûص + /// + virtual bool Execute() = 0; + + /// + /// ûصinvoke threadص + /// + virtual void Invoke(lua_State* invokeThreaad) = 0; + + protected: + + // ȡص + Luax::LuaxMemberRef mCallback; + + }; + + } +} + +namespace AEThreading = AsuraEngine::Threading; + +#endif
\ No newline at end of file diff --git a/source/libs/asura-lib-utils/threading/thread.cpp b/source/libs/asura-lib-utils/threading/thread.cpp new file mode 100644 index 0000000..0f4f5da --- /dev/null +++ b/source/libs/asura-lib-utils/threading/thread.cpp @@ -0,0 +1,272 @@ +#include "thread.h" + +#include "thread_impl_win32.h" +#include "thread_impl_posix.h" +#include "thread_impl_sdl.h" +#include "thread_impl_std.h" + +namespace AsuraEngine +{ + namespace Threading + { + + Thread::Thread(lua_State* luaThread, ThreadType type /*= THREAD_TYPE_DEFERRED*/, uint sleepTime /*= 0*/, const std::string& name /*= ""*/) + : mName(name) + , mState(THREAD_STATE_IDLE) + , mType(type) + , mLuaThread(luaThread) + , mCallbackThread(nullptr) + , mSleepTime(sleepTime) + { + LUAX_STATE(luaThread); + if (type == THREAD_TYPE_IMMEDIATE) + { + Luax::LuaxVM* vm = state.GetVM(); + ASSERT(vm); + mCallbackThread = vm->CreateThread(); + ASSERT(mCallbackThread); + SetLuaxMemberRef(state, mCallbackThreadRef, -1); + state.Pop(); // callback thread + } + } + + Thread::~Thread() + { + if (mImpl) + { + delete mImpl; + mImpl = nullptr; + } + } + + bool Thread::AddTask(Task* task) + { + lock(mTaskQueueMutex); + mTaskQueue.push(task); + return true; + } + + uint Thread::GetTaskCount() + { + return mTaskQueue.size(); + } + + void Thread::Idle() + { + mState = THREAD_STATE_IDLE; + } + +#define try_start_thread(impl)\ + if (!mImpl) \ + { \ + mImpl = new impl(); \ + if (!mImpl->Start(this, stacksize)) \ + { \ + delete mImpl; \ + mImpl = nullptr; \ + } \ + } + + bool Thread::Start(bool isDaemon /*= true*/, uint32 stacksize /*= 0*/) + { + if (mState != THREAD_STATE_IDLE) + return false; + + // Ѿһ֮ǰģر + if (mImpl) + { + delete mImpl; + mImpl = nullptr; + } + +#if ASURA_THREAD_WIN32 + try_start_thread(ThreadImplWin32); +#endif + + if (!mImpl) + return false; + + mIsDaemon = isDaemon; + mStateMutex.Lock(); + mState = THREAD_STATE_RUNNING; + mStateMutex.Unlock(); + } + + void Thread::Pause() + { + ASSERT(mImpl); + + lock(mStateMutex); + mState = THREAD_STATE_PAUSED; + } + + void Thread::Resume() + { + ASSERT(mImpl); + + lock(mStateMutex); + if(mState == THREAD_STATE_PAUSED) + mState = THREAD_STATE_RUNNING; + } + + void Thread::Stop() + { + ASSERT(mImpl); + + lock(mStateMutex); + mState = THREAD_STATE_STOPPED; + } + + void Thread::PauseSync() + { + Pause(); + wait(mSemPause); + } + + void Thread::ResumeSync() + { + Resume(); + wait(mSemResume); + } + + void Thread::StopSync() + { + Stop(); + wait(mSemStop); + } + + void Thread::Join() + { + ASSERT(mImpl); + mImpl->Join(); + } + + ThreadState Thread::GetState() + { + ThreadState state; + mStateMutex.Lock(); + state = mState; + mStateMutex.Unlock(); + return state; + } + + bool Thread::IsRunning() + { + ASSERT(mImpl); + + return GetState() == THREAD_STATE_RUNNING; + } + + bool Thread::IsPaused() + { + ASSERT(mImpl); + + return GetState() == THREAD_STATE_PAUSED; + } + + bool Thread::IsStopped() + { + ASSERT(mImpl); + + return GetState() == THREAD_STATE_STOPPED; + } + + bool Thread::IsCurrent() + { + ASSERT(mImpl); + + return mImpl->IsCurrent(); + } + + const std::string& Thread::GetName() + { + return mName; + } + + void Thread::Process() + { + LUAX_STATE(mLuaThread); + + do{ + if (IsRunning()) + { + while (!mTaskQueue.empty()) + { + Task* task = mTaskQueue.front(); + if (task && task->Execute()) + { + if (mType == THREAD_TYPE_DEFERRED) + { + mFinishedMutex.Lock(); + mFinishedTasks.push(task); + mFinishedMutex.Unlock(); + } + else if (mType == THREAD_TYPE_IMMEDIATE) + { + task->Invoke(mCallbackThread); + this->LuaxRelease<Task>(state, task); + } + mTaskQueueMutex.Lock(); + mTaskQueue.pop(); + mTaskQueueMutex.Unlock(); + } + } + } + + // ˳ѭ + if (IsStopped()) + break; + + // CPUʹ + Sleep(mSleepTime); + + } while (mIsDaemon); + + // ػ̣߳еstop״̬ + if (!mIsDaemon) + Stop(); + + signal(mSemStop); + + // ״̬ΪIdle + Idle(); + } + + /// + /// ӳģʽص + /// + void Thread::Post() + { + ASSERT(mType == THREAD_TYPE_DEFERRED); + + LUAX_STATE(mLuaThread); + while (!mFinishedTasks.empty()) + { + Task* task = mFinishedTasks.front(); + if (task) + { + task->Invoke(mLuaThread); + this->LuaxRelease<Task>(state, task); + mFinishedMutex.Lock(); + mFinishedTasks.pop(); + mFinishedMutex.Unlock(); + } + } + } + + void Thread::Sleep(uint ms) + { + ASSERT(mImpl); + if (mImpl) + { + mImpl->Sleep(ms); + } + } + + void Thread::SetSleepTime(uint ms) + { + mSleepTime = ms; + } + + } +}
\ No newline at end of file diff --git a/source/libs/asura-lib-utils/threading/thread.h b/source/libs/asura-lib-utils/threading/thread.h new file mode 100644 index 0000000..0e75770 --- /dev/null +++ b/source/libs/asura-lib-utils/threading/thread.h @@ -0,0 +1,221 @@ +#ifndef __ASURA_THREAD_H__ +#define __ASURA_THREAD_H__ + +#include <string> +#include <queue> + +#include <asura-lib-utils/scripting/portable.hpp> + +#include "task.h" +#include "mutex.h" +#include "semaphore.h" + +namespace AsuraEngine +{ + namespace Threading + { + + class ThreadImpl; + + /// + /// ̵߳ļֲͬʵ֣ + /// 1: Deferredӳģʽ߳ϵɺҪ̵ֶ߳Post + /// ̵߳ص첽Ϊͬlua_Stateͻ⡣ + /// 2: Immediateģʽÿһ߳άһlua_newthreadlua_State + /// صڲͬlua_Stateеãⲻ̷ͬ߳ͬһlua_State + /// + enum ThreadType + { + THREAD_TYPE_DEFERRED, + THREAD_TYPE_IMMEDIATE, + }; + + 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: + + 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(); + + /// + /// ִС + /// + void Process(); + + const std::string& GetName(); + + /// + /// ص + /// + void Post(); + + /// + /// ߺ + /// + 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(_Post); + LUAX_DECL_METHOD(_GetName); + LUAX_DECL_METHOD(_GetType); + LUAX_DECL_METHOD(_GetState); + LUAX_DECL_METHOD(_SetSleepTime); + + //----------------------------------------------------------------------------// + + /// + /// ˴Ƿػģʽ + /// + bool mIsDaemon; + + lua_State* mLuaThread; + + ThreadImpl* mImpl; + std::string mName; + ThreadType mType; + uint mSleepTime; + + ThreadState mState; + Mutex mStateMutex; + + /// + /// ͬصź + /// + Semaphore mSemPause; + Semaphore mSemResume; + Semaphore mSemStop; + + /// + /// С + /// + std::queue<Task*> mTaskQueue; + Mutex mTaskQueueMutex; + + /// + /// ӳģʽʹ + /// + std::queue<Task*> mFinishedTasks; + Mutex mFinishedMutex; + + /// + /// ģʽʹãصʹõlua߳ + /// + lua_State* mCallbackThread; + Luax::LuaxMemberRef mCallbackThreadRef; + + }; + + /// + /// ̵߳ľʵ֣ûģһֲԣ + /// 1: win32 + /// 2: posix + /// 3: SDL + /// 4: std::thread + /// + ASURA_ABSTRACT class ThreadImpl + { + public: + ThreadImpl() {}; + virtual ~ThreadImpl() {}; + + virtual bool Start(Thread* 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; + + }; + + } +} + +#endif
\ No newline at end of file diff --git a/source/libs/asura-lib-utils/threading/thread_impl_posix.cpp b/source/libs/asura-lib-utils/threading/thread_impl_posix.cpp new file mode 100644 index 0000000..d2ad7af --- /dev/null +++ b/source/libs/asura-lib-utils/threading/thread_impl_posix.cpp @@ -0,0 +1,9 @@ +#include "thread_impl_posix.h" + +namespace AsuraEngine +{ + namespace Threading + { + + } +}
\ No newline at end of file diff --git a/source/libs/asura-lib-utils/threading/thread_impl_posix.h b/source/libs/asura-lib-utils/threading/thread_impl_posix.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/source/libs/asura-lib-utils/threading/thread_impl_posix.h diff --git a/source/libs/asura-lib-utils/threading/thread_impl_sdl.cpp b/source/libs/asura-lib-utils/threading/thread_impl_sdl.cpp new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/source/libs/asura-lib-utils/threading/thread_impl_sdl.cpp diff --git a/source/libs/asura-lib-utils/threading/thread_impl_sdl.h b/source/libs/asura-lib-utils/threading/thread_impl_sdl.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/source/libs/asura-lib-utils/threading/thread_impl_sdl.h diff --git a/source/libs/asura-lib-utils/threading/thread_impl_std.cpp b/source/libs/asura-lib-utils/threading/thread_impl_std.cpp new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/source/libs/asura-lib-utils/threading/thread_impl_std.cpp diff --git a/source/libs/asura-lib-utils/threading/thread_impl_std.h b/source/libs/asura-lib-utils/threading/thread_impl_std.h new file mode 100644 index 0000000..0e7d3da --- /dev/null +++ b/source/libs/asura-lib-utils/threading/thread_impl_std.h @@ -0,0 +1,43 @@ +#ifndef __ASURA_THREAD_STD_H__ +#define __ASURA_THREAD_STD_H__ + +#include "../utils_config.h" + +#if ASURA_THREAD_STD + +#include <windows.h> + +#include "thread.h" + +namespace AsuraEngine +{ + namespace Threading + { + + /// + /// Threadstd::threadʵ֡ + /// + class ThreadImplSTD : public ThreadImpl + { + public: + + ThreadImplSTD(); + ~ThreadImplSTD(); + + bool Start(Thread* thread, uint32 stacksize) override; + void Join() override; + void Kill() override; + + bool IsRunning() override; + bool IsCurrent() override; + + private: + + }; + + } +} + +#endif // #if ASURA_THREAD_STD + +#endif // __ASURA_THREAD_STD_H__
\ No newline at end of file diff --git a/source/libs/asura-lib-utils/threading/thread_impl_win32.cpp b/source/libs/asura-lib-utils/threading/thread_impl_win32.cpp new file mode 100644 index 0000000..6871c2d --- /dev/null +++ b/source/libs/asura-lib-utils/threading/thread_impl_win32.cpp @@ -0,0 +1,76 @@ +#include "thread_impl_win32.h" +#include "thread.h" + +#include <iostream> + +namespace AsuraEngine +{ + namespace Threading + { + + static DWORD WINAPI _thread_win32_runner(LPVOID param) + { + Thread* thread = (Thread*)param; + thread->Process(); + return 0; + } + + ThreadImplWin32::ThreadImplWin32() + { + } + + ThreadImplWin32::~ThreadImplWin32() + { + if (!mHandle) return; + ::CloseHandle(mHandle); + mHandle = 0; + } + + bool ThreadImplWin32::Start(Thread* thread, uint32 stacksize/*=0*/) + { + assert(!IsRunning()); + mHandle = ::CreateThread( + NULL + , stacksize + , _thread_win32_runner + , thread + , 0 /*е*/ + , NULL); + + return mHandle; + } + + void ThreadImplWin32::Join() + { + // ̵߳ȴ̷߳ + ::WaitForSingleObject(mHandle, INFINITE); + } + + void ThreadImplWin32::Kill() + { + ::TerminateThread(mHandle, FALSE); + } + + void ThreadImplWin32::Sleep(uint ms) + { + ::Sleep(ms); + } + + bool ThreadImplWin32::IsRunning() + { + if (mHandle) { + DWORD exitCode = 0; + // https://blog.csdn.net/yuanmeng567/article/details/19485719 + ::GetExitCodeThread(mHandle, &exitCode); + return exitCode == STILL_ACTIVE; + } + return false; + } + + bool ThreadImplWin32::IsCurrent() + { + return mHandle == ::GetCurrentThread(); + } + + } +}
\ No newline at end of file diff --git a/source/libs/asura-lib-utils/threading/thread_impl_win32.h b/source/libs/asura-lib-utils/threading/thread_impl_win32.h new file mode 100644 index 0000000..a22aeef --- /dev/null +++ b/source/libs/asura-lib-utils/threading/thread_impl_win32.h @@ -0,0 +1,47 @@ +#ifndef __ASURA_THREAD_WIN32_H__ +#define __ASURA_THREAD_WIN32_H__ + +#include "../utils_config.h" + +#if ASURA_THREAD_WIN32 + +#include <windows.h> + +#include "thread.h" + +namespace AsuraEngine +{ + namespace Threading + { + + /// + /// Threadwin32ʵ֡ + /// + class ThreadImplWin32 : public ThreadImpl + { + public: + + ThreadImplWin32(); + ~ThreadImplWin32(); + + bool Start(Thread* thread, uint32 stacksize) override; + void Join() override; + void Kill() override; + + void Sleep(uint ms) override; + + bool IsRunning() override; + bool IsCurrent() override; + + private: + + HANDLE mHandle; + + }; + + } +} + +#endif // #if ASURA_THREAD_WIN32 + +#endif // __ASURA_THREAD_WIN32_H__
\ No newline at end of file diff --git a/source/libs/asura-lib-utils/threading/thread_task.cpp b/source/libs/asura-lib-utils/threading/thread_task.cpp new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/source/libs/asura-lib-utils/threading/thread_task.cpp diff --git a/source/libs/asura-lib-utils/threading/thread_task.h b/source/libs/asura-lib-utils/threading/thread_task.h new file mode 100644 index 0000000..1ea0a1a --- /dev/null +++ b/source/libs/asura-lib-utils/threading/thread_task.h @@ -0,0 +1,44 @@ +#ifndef __ASURA_THRAD_TASK_H__ +#define __ASURA_THRAD_TASK_H__ + +#include <asura-lib-utils/type.h> +#include <asura-lib-utils/scripting/portable.hpp> + +namespace AsuraEngine +{ + namespace Threading + { + + /// + /// ϣһ̴̳߳TaskдExecute + /// + ASURA_ABSTRACT class ThreadTask + : virtual public AEScripting::NativeAccessor + { + public: + + ThreadTask(); + virtual ~ThreadTask(); + + /// + /// ִɺtrueûص + /// + virtual bool Execute() = 0; + + /// + /// ûص + /// + virtual void Invoke() = 0; + + protected: + + Luax::LuaxMemberRef mCallback; + + }; + + } +} + +namespace AEThreading = AsuraEngine::Threading; + +#endif
\ No newline at end of file |