summaryrefslogtreecommitdiff
path: root/Client/Source/Threading
diff options
context:
space:
mode:
Diffstat (limited to 'Client/Source/Threading')
-rw-r--r--Client/Source/Threading/Job.cpp13
-rw-r--r--Client/Source/Threading/Job.h17
-rw-r--r--Client/Source/Threading/JobSystem.cpp56
-rw-r--r--Client/Source/Threading/JobSystem.h25
-rw-r--r--Client/Source/Threading/Mutex.cpp27
-rw-r--r--Client/Source/Threading/Mutex.h39
-rw-r--r--Client/Source/Threading/Semaphore.cpp0
-rw-r--r--Client/Source/Threading/Semaphore.h0
-rw-r--r--Client/Source/Threading/Thread.cpp70
-rw-r--r--Client/Source/Threading/Thread.h71
-rw-r--r--Client/Source/Threading/WorkThread.cpp50
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