diff --git a/sdk/Windows/Helpers.h b/sdk/Windows/Helpers.h index f6875af..5b3d6f7 100644 --- a/sdk/Windows/Helpers.h +++ b/sdk/Windows/Helpers.h @@ -6,6 +6,7 @@ #include #include #include +#include using namespace std; namespace SMX @@ -99,6 +100,42 @@ public: private: Mutex &m_Mutex; }; + + +class Event +{ +public: + Event(Mutex &lock): + m_Lock(lock) + { + m_hEvent = make_shared(CreateEvent(NULL, false, false, NULL)); + } + + void Set() + { + SetEvent(m_hEvent->value()); + } + + // Unlock m_Lock, wait up to iDelayMilliseconds for the event to be set, + // then lock m_Lock. If iDelayMilliseconds is -1, wait forever. + void Wait(int iDelayMilliseconds) + { + if(iDelayMilliseconds == -1) + iDelayMilliseconds = INFINITE; + + m_Lock.AssertLockedByCurrentThread(); + + m_Lock.Unlock(); + vector aHandles = { m_hEvent->value() }; + WaitForSingleObjectEx(m_hEvent->value(), iDelayMilliseconds, true); + m_Lock.Lock(); + } + +private: + shared_ptr m_hEvent; + Mutex &m_Lock; +}; + } #endif diff --git a/sdk/Windows/SMX.vcxproj b/sdk/Windows/SMX.vcxproj index e6017b1..0b77f94 100644 --- a/sdk/Windows/SMX.vcxproj +++ b/sdk/Windows/SMX.vcxproj @@ -20,6 +20,7 @@ + @@ -30,6 +31,7 @@ + {C5FC0823-9896-4B7C-BFE1-B60DB671A462} diff --git a/sdk/Windows/SMX.vcxproj.filters b/sdk/Windows/SMX.vcxproj.filters index 573ae71..a048bd5 100644 --- a/sdk/Windows/SMX.vcxproj.filters +++ b/sdk/Windows/SMX.vcxproj.filters @@ -34,6 +34,9 @@ Source Files + + Source Files + @@ -60,5 +63,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/sdk/Windows/SMXHelperThread.cpp b/sdk/Windows/SMXHelperThread.cpp index 485c405..7166dcb 100644 --- a/sdk/Windows/SMXHelperThread.cpp +++ b/sdk/Windows/SMXHelperThread.cpp @@ -1,31 +1,10 @@ #include "SMXHelperThread.h" - -#include using namespace SMX; -SMX::SMXHelperThread::SMXHelperThread(const string &sThreadName) -{ - m_hEvent = make_shared(CreateEvent(NULL, false, false, NULL)); - - // Start the thread. - m_hThread = CreateThread(NULL, 0, ThreadMainStart, this, 0, &m_iThreadId); - SMX::SetThreadName(m_iThreadId, sThreadName); -} - -SMX::SMXHelperThread::~SMXHelperThread() -{ -} - -void SMX::SMXHelperThread::SetHighPriority(bool bHighPriority) -{ - SetThreadPriority( m_hThread, THREAD_PRIORITY_HIGHEST ); -} - -DWORD WINAPI SMX::SMXHelperThread::ThreadMainStart(void *self_) +SMX::SMXHelperThread::SMXHelperThread(const string &sThreadName): + SMXThread(m_Lock) { - SMXHelperThread *self = (SMXHelperThread *) self_; - self->ThreadMain(); - return 0; + Start(sThreadName); } void SMX::SMXHelperThread::ThreadMain() @@ -44,26 +23,13 @@ void SMX::SMXHelperThread::ThreadMain() m_Lock.Unlock(); for(auto &func: funcs) func(); - - WaitForSingleObjectEx(m_hEvent->value(), 250, true); m_Lock.Lock(); + + m_Event.Wait(250); } m_Lock.Unlock(); } -void SMX::SMXHelperThread::Shutdown() -{ - if(m_hThread == INVALID_HANDLE_VALUE) - return; - - // Tell the thread to shut down, and wait for it before returning. - m_bShutdown = true; - SetEvent(m_hEvent->value()); - - WaitForSingleObject(m_hThread, INFINITE); - m_hThread = INVALID_HANDLE_VALUE; -} - void SMX::SMXHelperThread::RunInThread(function func) { m_Lock.AssertNotLockedByCurrentThread(); @@ -71,11 +37,6 @@ void SMX::SMXHelperThread::RunInThread(function func) // Add func to the list, and poke the event to wake up the thread if needed. m_Lock.Lock(); m_FunctionsToCall.push_back(func); - SetEvent(m_hEvent->value()); + m_Event.Set(); m_Lock.Unlock(); } - -bool SMX::SMXHelperThread::IsCurrentThread() const -{ - return GetCurrentThreadId() == m_iThreadId; -} diff --git a/sdk/Windows/SMXHelperThread.h b/sdk/Windows/SMXHelperThread.h index 18ad24d..b19ad28 100644 --- a/sdk/Windows/SMXHelperThread.h +++ b/sdk/Windows/SMXHelperThread.h @@ -2,6 +2,7 @@ #define SMXHelperThread_h #include "Helpers.h" +#include "SMXThread.h" #include #include @@ -10,34 +11,19 @@ using namespace std; namespace SMX { -class SMXHelperThread +class SMXHelperThread: public SMXThread { public: SMXHelperThread(const string &sThreadName); - ~SMXHelperThread(); - - // Raise the priority of the helper thread. - void SetHighPriority(bool bHighPriority); - - // Shut down the thread. Any calls queued by RunInThread will complete before - // this returns. - void Shutdown(); - + // Call func asynchronously from the helper thread. void RunInThread(function func); - // Return true if this is the calling thread. - bool IsCurrentThread() const; - private: - static DWORD WINAPI ThreadMainStart(void *self_); void ThreadMain(); - DWORD m_iThreadId = 0; + // Helper threads use their independent lock. SMX::Mutex m_Lock; - shared_ptr m_hEvent; - bool m_bShutdown = false; - HANDLE m_hThread = INVALID_HANDLE_VALUE; vector> m_FunctionsToCall; }; } diff --git a/sdk/Windows/SMXThread.cpp b/sdk/Windows/SMXThread.cpp new file mode 100644 index 0000000..4fb06b8 --- /dev/null +++ b/sdk/Windows/SMXThread.cpp @@ -0,0 +1,49 @@ +#include "SMXThread.h" + +using namespace std; +using namespace SMX; + +SMXThread::SMXThread(Mutex &lock): + m_Lock(lock), + m_Event(lock) +{ +} + +void SMX::SMXThread::SetHighPriority(bool bHighPriority) +{ + if(m_hThread == INVALID_HANDLE_VALUE) + throw exception("SetHighPriority called while the thread isn't running"); + + SetThreadPriority(m_hThread, THREAD_PRIORITY_HIGHEST); +} + +bool SMX::SMXThread::IsCurrentThread() const +{ + return GetCurrentThreadId() == m_iThreadId; +} + +void SMXThread::Start(string name) +{ + // Start the thread. + m_hThread = CreateThread(NULL, 0, ThreadMainStart, this, 0, &m_iThreadId); + SMX::SetThreadName(m_iThreadId, name); +} + +void SMXThread::Shutdown() +{ + m_Lock.AssertNotLockedByCurrentThread(); + + // Shut down the thread and wait for it to exit. + m_bShutdown = true; + m_Event.Set(); + + WaitForSingleObject(m_hThread, INFINITE); + m_hThread = INVALID_HANDLE_VALUE; +} + +DWORD WINAPI SMXThread::ThreadMainStart(void *self_) +{ + SMXThread *self = (SMXThread *) self_; + self->ThreadMain(); + return 0; +} diff --git a/sdk/Windows/SMXThread.h b/sdk/Windows/SMXThread.h new file mode 100644 index 0000000..ea672f0 --- /dev/null +++ b/sdk/Windows/SMXThread.h @@ -0,0 +1,45 @@ +#ifndef SMXThread_h +#define SMXThread_h + +// A base class for a thread. +#include "Helpers.h" +#include + +namespace SMX +{ + +class SMXThread +{ +public: + SMXThread(SMX::Mutex &lock); + + // Raise the priority of the thread. + void SetHighPriority(bool bHighPriority); + + // Start the thread, giving it a name for debugging. + void Start(std::string name); + + // Shut down the thread. This function won't return until the thread + // has been stopped. + void Shutdown(); + + // Return true if this is the calling thread. + bool IsCurrentThread() const; + + // The derived class implements this. + virtual void ThreadMain() = 0; + +protected: + static DWORD WINAPI ThreadMainStart(void *self); + + SMX::Mutex &m_Lock; + SMX::Event m_Event; + bool m_bShutdown = false; + +private: + HANDLE m_hThread = INVALID_HANDLE_VALUE; + DWORD m_iThreadId = 0; +}; +} + +#endif