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  | 
