diff options
Diffstat (limited to 'Client/Source/Threading')
-rw-r--r-- | Client/Source/Threading/Job.cpp | 13 | ||||
-rw-r--r-- | Client/Source/Threading/Job.h | 17 | ||||
-rw-r--r-- | Client/Source/Threading/JobSystem.cpp | 56 | ||||
-rw-r--r-- | Client/Source/Threading/JobSystem.h | 25 | ||||
-rw-r--r-- | Client/Source/Threading/Mutex.cpp | 27 | ||||
-rw-r--r-- | Client/Source/Threading/Mutex.h | 39 | ||||
-rw-r--r-- | Client/Source/Threading/Semaphore.cpp | 0 | ||||
-rw-r--r-- | Client/Source/Threading/Semaphore.h | 0 | ||||
-rw-r--r-- | Client/Source/Threading/Thread.cpp | 70 | ||||
-rw-r--r-- | Client/Source/Threading/Thread.h | 71 | ||||
-rw-r--r-- | Client/Source/Threading/WorkThread.cpp | 50 |
11 files changed, 368 insertions, 0 deletions
diff --git a/Client/Source/Threading/Job.cpp b/Client/Source/Threading/Job.cpp new file mode 100644 index 0000000..3bfdb4d --- /dev/null +++ b/Client/Source/Threading/Job.cpp @@ -0,0 +1,13 @@ +#include "Job.h" +#include "../Utilities/UIDGenerator.h" + +static UIDGenerator s_JobIDGenerator; + +Job::Job() + : m_ID(s_JobIDGenerator.GenUID()) +{ +} + +Job::~Job() +{ +} diff --git a/Client/Source/Threading/Job.h b/Client/Source/Threading/Job.h new file mode 100644 index 0000000..db89feb --- /dev/null +++ b/Client/Source/Threading/Job.h @@ -0,0 +1,17 @@ +#pragma once + +// 任务的抽象基类 +class Job +{ +public: + Job(); + virtual ~Job(); + + virtual void Process() = 0; + virtual bool IsFinished() = 0; + virtual void Dispacth(void* param) = 0; // call in main thread + +protected: + int m_ID; // Job ID + +};
\ No newline at end of file diff --git a/Client/Source/Threading/JobSystem.cpp b/Client/Source/Threading/JobSystem.cpp new file mode 100644 index 0000000..378d74f --- /dev/null +++ b/Client/Source/Threading/JobSystem.cpp @@ -0,0 +1,56 @@ +#include "JobSystem.h" +#include "../Debug/Log.h" + +JobSystem::JobSystem() + : m_Initialized(false) +{ + +} + +JobSystem::~JobSystem() +{ + +} + +void JobSystem::Initilize(int workThreadCount) +{ + if (m_Initialized) + { + log_error("JobSystem has already initialized."); + return; + } + + if (workThreadCount <= 0) + return; + + m_ThreadCount = workThreadCount; + m_Cur = 0; + + for (int i = 0; i < workThreadCount; ++i) + { + WorkThread* thread = new WorkThread(); + thread->Resume(); + m_Threads.push_back(thread); + } + + m_Initialized = true; +} + +void JobSystem::Dispatch(void* param) +{ + for (int i = 0; i < m_Threads.size(); ++i) + { + m_Threads[i]->Dispatch(param); + } +} + +void JobSystem::AddJobAtEnd(Job* job) +{ + WorkThread* thread = SelectThread(); + thread->AddJobAtEnd(job); +} + +WorkThread* JobSystem::SelectThread() +{ + return m_Threads[(++m_Cur)% m_ThreadCount]; +}
\ No newline at end of file diff --git a/Client/Source/Threading/JobSystem.h b/Client/Source/Threading/JobSystem.h new file mode 100644 index 0000000..ded4370 --- /dev/null +++ b/Client/Source/Threading/JobSystem.h @@ -0,0 +1,25 @@ +#pragma once +#include "../Utilities/Singleton.h" +#include "../Threading/Thread.h" +#include <vector> + +class JobSystem : public Singleton<JobSystem> +{ +public: + JobSystem(); + ~JobSystem(); + + void AddJobAtEnd(Job* job); + + void Initilize(int workThreadCount = 1); + void Dispatch(void* param); + +private: + WorkThread* SelectThread(); + + bool m_Initialized; + std::vector<WorkThread*> m_Threads; + int m_Cur; + int m_ThreadCount; + +};
\ No newline at end of file diff --git a/Client/Source/Threading/Mutex.cpp b/Client/Source/Threading/Mutex.cpp new file mode 100644 index 0000000..cda7e89 --- /dev/null +++ b/Client/Source/Threading/Mutex.cpp @@ -0,0 +1,27 @@ +#include "Thread.h" +#include "Mutex.h" + +#include "../Utilities/Type.h" + +Mutex::Mutex() +{ + m_Handle = ::CreateMutex(NULL, FALSE, NULL); + if (!m_Handle) + throw ThreadException("Cant use win32 mutex."); +} + +Mutex::~Mutex() +{ + ::CloseHandle(m_Handle); + m_Handle = NULL; +} + +void Mutex::LockSelf() +{ + ::WaitForSingleObject(m_Handle, (~(uint32)0)); +} + +void Mutex::UnlockSelf() +{ + ::ReleaseMutex(m_Handle); +}
\ No newline at end of file diff --git a/Client/Source/Threading/Mutex.h b/Client/Source/Threading/Mutex.h new file mode 100644 index 0000000..eed69aa --- /dev/null +++ b/Client/Source/Threading/Mutex.h @@ -0,0 +1,39 @@ +#pragma once +#include <windows.h> + +class Mutex +{ +public: + Mutex(); + ~Mutex(); + + void LockSelf(); + void UnlockSelf(); + +private: + HANDLE m_Handle; + +}; + + +class MutexLocker +{ +public: + MutexLocker(Mutex& mutex) + : m(mutex) + { + m.LockSelf(); + }; + ~MutexLocker() + { + m.UnlockSelf(); + } + operator bool() { return false; }; +private: + void* operator new(size_t); + Mutex& m; +}; + +#define Lock(m) \ +if(MutexLocker lock_##m = m){} else + diff --git a/Client/Source/Threading/Semaphore.cpp b/Client/Source/Threading/Semaphore.cpp new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Client/Source/Threading/Semaphore.cpp diff --git a/Client/Source/Threading/Semaphore.h b/Client/Source/Threading/Semaphore.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Client/Source/Threading/Semaphore.h diff --git a/Client/Source/Threading/Thread.cpp b/Client/Source/Threading/Thread.cpp new file mode 100644 index 0000000..0bede98 --- /dev/null +++ b/Client/Source/Threading/Thread.cpp @@ -0,0 +1,70 @@ +#include <string> +#include "Thread.h" +#include "../Utilities/Assert.h" +#include "../Utilities/Type.h" + +static std::string s_ThreadErr; + +static DWORD WINAPI ThreadMain(LPVOID param) +{ + Thread* thread = (Thread*)param; + thread->Run(); + return NULL; +} + +Thread::Thread(uint32 stacksize) +{ + m_Handle = ::CreateThread( + NULL + , stacksize + , ThreadMain + , this + , CREATE_SUSPENDED + , NULL); + if (m_Handle == 0) + { + s_ThreadErr = "Create Thread Failed. ErrorCode=" + std::to_string(GetLastError()); + throw ThreadException(s_ThreadErr.c_str()); + } +} + +Thread::~Thread() +{ + CloseHandle(m_Handle); +} + +void Thread::Resume() +{ + ::ResumeThread(m_Handle); +} + +bool Thread::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; +} + +void Thread::Join() +{ + ::WaitForSingleObject(m_Handle, INFINITE); +} + +void Thread::Kill() +{ + ::TerminateThread(m_Handle, FALSE); +} + +void Thread::Sleep(uint ms) +{ + ::Sleep(ms); +} + +bool Thread::IsCurrent() +{ + return m_Handle == ::GetCurrentThread(); +} diff --git a/Client/Source/Threading/Thread.h b/Client/Source/Threading/Thread.h new file mode 100644 index 0000000..77d8dff --- /dev/null +++ b/Client/Source/Threading/Thread.h @@ -0,0 +1,71 @@ +#pragma once +#include <windows.h> +#include <vector> +#include <exception> + +#include "../Utilities/Type.h" + +#include "Job.h" +#include "Mutex.h" + +class ThreadException : public std::exception +{ +public: + ThreadException(const char* what) + : std::exception(what) + { + } +}; + +class Thread +{ +public: + Thread(uint32 stacksize = 0)/*throw ThreadExeception*/; + virtual ~Thread(); + + virtual void Run() = 0; + + virtual void Resume(); + virtual void Join() ; + virtual void Kill() ; + + virtual void Sleep(uint ms) ; + + virtual bool IsRunning() ; + virtual bool IsCurrent() ; + +protected: + HANDLE m_Handle; + +}; + +// 任务系统的线程 +class WorkThread : public Thread +{ +public: + void Run() override; + void Dispatch(void* param); // call in main thread + + void AddJobAtEnd(Job* job); + +private: + Mutex m_PendingMutex; + Mutex m_FinishedMutex; + + std::vector<Job*> m_PendingJobs; + std::vector<Job*> m_FinishedJobs; + +}; + +// 执行小段代码的线程 +class CodePieceThread : public Thread +{ +public: + typedef void(*CodePiece)(); + + void Run() override; + +private: + std::vector<CodePiece> m_CodePieces; + +};
\ No newline at end of file diff --git a/Client/Source/Threading/WorkThread.cpp b/Client/Source/Threading/WorkThread.cpp new file mode 100644 index 0000000..4ea6262 --- /dev/null +++ b/Client/Source/Threading/WorkThread.cpp @@ -0,0 +1,50 @@ +#include "Thread.h" + +#include "../Debug/Log.h" + +void WorkThread::Run() +{ + while (true) + { + Lock(m_PendingMutex) + { + for (auto iter = m_PendingJobs.begin(); iter != m_PendingJobs.end();) + { + Job* job = *iter; + job->Process(); + if (job->IsFinished()) + { + Lock(m_FinishedMutex) { + m_FinishedJobs.push_back(job); + } + iter = m_PendingJobs.erase(iter); + continue; + } + ++iter; + } + if (m_PendingJobs.size() == 0) + ::Sleep(100); + } + } +} + +void WorkThread::Dispatch(void* param) +{ + Lock(m_FinishedMutex) + { + for (int i = 0; i < m_FinishedJobs.size(); ++i) + { + m_FinishedJobs[i]->Dispacth(param); + delete m_FinishedJobs[i]; + } + m_FinishedJobs.clear(); + } +} + +void WorkThread::AddJobAtEnd(Job* job) +{ + Lock(m_PendingMutex) + { + m_PendingJobs.push_back(job); + } +}
\ No newline at end of file |