aboutsummaryrefslogtreecommitdiff
path: root/src/libjin/threads
diff options
context:
space:
mode:
Diffstat (limited to 'src/libjin/threads')
-rw-r--r--src/libjin/threads/thread.cpp582
-rw-r--r--src/libjin/threads/thread.h276
2 files changed, 429 insertions, 429 deletions
diff --git a/src/libjin/threads/thread.cpp b/src/libjin/threads/thread.cpp
index 1c35efb..0dfa53b 100644
--- a/src/libjin/threads/thread.cpp
+++ b/src/libjin/threads/thread.cpp
@@ -5,297 +5,297 @@
namespace JinEngine
{
- namespace Threads
- {
-
- class Mutex
- {
- public:
- Mutex();
- ~Mutex();
-
- void lock();
- void unlock();
- private:
- #if jin_thread == jin_thread_sdl
- SDL_mutex* mutex;
- #endif
- friend class Conditional;
- };
-
- // ̼߳signal wait
- class Conditional
- {
- public:
- Conditional();
- ~Conditional();
- void signal();
- void broadcast();
- bool wait(Mutex* mutex, int timeout = -1);
- private:
- #if jin_thread == jin_thread_sdl
- SDL_cond* cond;
- #endif
- };
-
- class Lock
- {
- public:
- Lock(Mutex* m) : mutex(m) {
- mutex->lock();
- }
-
- Lock(Mutex& m) : mutex(&m) {
- mutex->lock();
- }
-
- ~Lock() {
- mutex->unlock();
- }
- private:
- Mutex* mutex;
-
- Lock(Lock&) {}
-
- };
-
- //////////////////////////////////////////////////////////////////////
-
- Mutex::Mutex()
- {
- #if jin_thread == jin_thread_sdl
- mutex = SDL_CreateMutex();
- #endif
- }
-
- Mutex::~Mutex()
- {
- #if jin_thread == jin_thread_sdl
- SDL_DestroyMutex(mutex);
- #endif
- }
-
- void Mutex::lock()
- {
- #if jin_thread == jin_thread_sdl
- SDL_LockMutex(mutex);
- #endif
- }
-
- void Mutex::unlock()
- {
- #if jin_thread == jin_thread_sdl
- SDL_UnlockMutex(mutex);
- #endif
- }
-
- //////////////////////////////////////////////////////////////////////
-
- Conditional::Conditional()
- {
- #if jin_thread == jin_thread_sdl
- cond = SDL_CreateCond();
- #endif
- }
-
- Conditional::~Conditional()
- {
- #if jin_thread == jin_thread_sdl
- SDL_DestroyCond(cond);
- #endif
- }
-
- void Conditional::signal()
- {
- #if jin_thread == jin_thread_sdl
- SDL_CondSignal(cond);
- #endif
- }
-
- void Conditional::broadcast()
- {
- #if jin_thread == jin_thread_sdl
- SDL_CondBroadcast(cond);
- #endif
- }
-
- bool Conditional::wait(Mutex* mutex, int timeout)
- {
- #if jin_thread == jin_thread_sdl
- if (timeout < 0)
- return !SDL_CondWait(cond, mutex->mutex);
- else
- return (SDL_CondWaitTimeout(cond, mutex->mutex, timeout) == 0);
- #endif
- }
-
- //////////////////////////////////////////////////////////////////////
-
- Thread::ThreadData::ThreadData(Mutex* m, Conditional* c)
- : mutex(m)
- , condition(c)
- , share()
- {
- }
-
- Thread::ThreadData::~ThreadData()
- {
- }
-
- void Thread::ThreadData::set(int slot, Variant value)
- {
- Lock l(mutex);
- share[slot] = value;
- }
-
- Thread::Variant Thread::ThreadData::get(int slot)
- {
- Lock l(mutex);
- return share[slot];
- }
-
- bool Thread::ThreadData::exist(int slot)
- {
- Lock l(mutex);
- return share.count(slot) == 1;
- }
-
- void Thread::ThreadData::remove(int slot)
- {
- Lock l(mutex);
- if (exist(slot))
- {
- share.erase(slot);
- }
- }
-
- //////////////////////////////////////////////////////////////////////
-
- Thread::Thread(const std::string tname, ThreadRunner runner)
- : name(tname)
- , running(false)
- , threadRunner(runner)
- {
- mutex = new Mutex();
- condition = new Conditional();
- common = new Thread::ThreadData(mutex, condition);
- }
-
- Thread::~Thread()
- {
- #if jin_thread == jin_thread_sdl
- #endif
- }
-
- const char* Thread::getName()
- {
- Lock l(mutex);
- return name.c_str();
- };
-
- bool Thread::isRunning()
- {
- Lock l(mutex);
- return running;
- };
-
- bool Thread::start(void* p)
- {
- Lock l(mutex);
- if (running)
- return false;
- if (handle)
- {
- #if jin_thread == jin_thread_sdl
- SDL_WaitThread(handle, nullptr);
- #endif
- }
- #if jin_thread == jin_thread_sdl
- handle = SDL_CreateThread(threadRunner, name.c_str(), p);
- #elif jin_thread == jin_thread_cpp
- handle = new std::thread();
- #endif
- return (running = (handle != nullptr));
- }
-
- void Thread::wait()
- {
- {
- Lock l(mutex);
- if (!handle)
- return;
- }
- #if jin_thread == jin_thread_sdl
- SDL_WaitThread(handle, nullptr);
- #endif
- Lock l(mutex);
- running = false;
- handle = nullptr;
- }
-
- void Thread::lock()
- {
- if (mutex != nullptr)
- mutex->lock();
- }
-
- void Thread::unlock()
- {
- if (mutex != nullptr)
- mutex->unlock();
- }
-
- void Thread::send(int slot, const Variant& value)
- {
- lock();
- common->set(slot, value);
- unlock();
- condition->broadcast();
- }
-
- bool Thread::receive(int slot)
- {
- return common->exist(slot);
- }
-
- Thread::Variant Thread::fetch(int slot)
- {
- Thread::Variant v = common->get(slot);
- return v;
- }
-
- Thread::Variant Thread::demand(int slot)
- {
- /**
- * pthread_mutex_lock(mtx);
- * while(pass == 0)
- * {
- * pthread_mutex_unlock(mtx);
- * pthread_cond_just_wait(cv);
- * pthread_mutex_lock(mtx);
- * }
- * pthread_mutex_unlock(mtx);
- */
- lock();
- while (!common->exist(slot))
- {
- if (common->exist(ThreadData::SLOT_ERROR))
- return 0;
- condition->wait(mutex);
- }
- Thread::Variant v = common->get(slot);
- unlock();
- return v;
- }
-
- void Thread::remove(int slot)
- {
- lock();
- common->remove(slot);
- unlock();
- }
-
- } // namespace Threads
+ namespace Threads
+ {
+
+ class Mutex
+ {
+ public:
+ Mutex();
+ ~Mutex();
+
+ void lock();
+ void unlock();
+ private:
+ #if jin_thread == jin_thread_sdl
+ SDL_mutex* mutex;
+ #endif
+ friend class Conditional;
+ };
+
+ // ̼߳signal wait
+ class Conditional
+ {
+ public:
+ Conditional();
+ ~Conditional();
+ void signal();
+ void broadcast();
+ bool wait(Mutex* mutex, int timeout = -1);
+ private:
+ #if jin_thread == jin_thread_sdl
+ SDL_cond* cond;
+ #endif
+ };
+
+ class Lock
+ {
+ public:
+ Lock(Mutex* m) : mutex(m) {
+ mutex->lock();
+ }
+
+ Lock(Mutex& m) : mutex(&m) {
+ mutex->lock();
+ }
+
+ ~Lock() {
+ mutex->unlock();
+ }
+ private:
+ Mutex* mutex;
+
+ Lock(Lock&) {}
+
+ };
+
+ //////////////////////////////////////////////////////////////////////
+
+ Mutex::Mutex()
+ {
+ #if jin_thread == jin_thread_sdl
+ mutex = SDL_CreateMutex();
+ #endif
+ }
+
+ Mutex::~Mutex()
+ {
+ #if jin_thread == jin_thread_sdl
+ SDL_DestroyMutex(mutex);
+ #endif
+ }
+
+ void Mutex::lock()
+ {
+ #if jin_thread == jin_thread_sdl
+ SDL_LockMutex(mutex);
+ #endif
+ }
+
+ void Mutex::unlock()
+ {
+ #if jin_thread == jin_thread_sdl
+ SDL_UnlockMutex(mutex);
+ #endif
+ }
+
+ //////////////////////////////////////////////////////////////////////
+
+ Conditional::Conditional()
+ {
+ #if jin_thread == jin_thread_sdl
+ cond = SDL_CreateCond();
+ #endif
+ }
+
+ Conditional::~Conditional()
+ {
+ #if jin_thread == jin_thread_sdl
+ SDL_DestroyCond(cond);
+ #endif
+ }
+
+ void Conditional::signal()
+ {
+ #if jin_thread == jin_thread_sdl
+ SDL_CondSignal(cond);
+ #endif
+ }
+
+ void Conditional::broadcast()
+ {
+ #if jin_thread == jin_thread_sdl
+ SDL_CondBroadcast(cond);
+ #endif
+ }
+
+ bool Conditional::wait(Mutex* mutex, int timeout)
+ {
+ #if jin_thread == jin_thread_sdl
+ if (timeout < 0)
+ return !SDL_CondWait(cond, mutex->mutex);
+ else
+ return (SDL_CondWaitTimeout(cond, mutex->mutex, timeout) == 0);
+ #endif
+ }
+
+ //////////////////////////////////////////////////////////////////////
+
+ Thread::ThreadData::ThreadData(Mutex* m, Conditional* c)
+ : mutex(m)
+ , condition(c)
+ , share()
+ {
+ }
+
+ Thread::ThreadData::~ThreadData()
+ {
+ }
+
+ void Thread::ThreadData::set(int slot, Variant value)
+ {
+ Lock l(mutex);
+ share[slot] = value;
+ }
+
+ Thread::Variant Thread::ThreadData::get(int slot)
+ {
+ Lock l(mutex);
+ return share[slot];
+ }
+
+ bool Thread::ThreadData::exist(int slot)
+ {
+ Lock l(mutex);
+ return share.count(slot) == 1;
+ }
+
+ void Thread::ThreadData::remove(int slot)
+ {
+ Lock l(mutex);
+ if (exist(slot))
+ {
+ share.erase(slot);
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+
+ Thread::Thread(const std::string tname, ThreadRunner runner)
+ : name(tname)
+ , running(false)
+ , threadRunner(runner)
+ {
+ mutex = new Mutex();
+ condition = new Conditional();
+ common = new Thread::ThreadData(mutex, condition);
+ }
+
+ Thread::~Thread()
+ {
+ #if jin_thread == jin_thread_sdl
+ #endif
+ }
+
+ const char* Thread::getName()
+ {
+ Lock l(mutex);
+ return name.c_str();
+ };
+
+ bool Thread::isRunning()
+ {
+ Lock l(mutex);
+ return running;
+ };
+
+ bool Thread::start(void* p)
+ {
+ Lock l(mutex);
+ if (running)
+ return false;
+ if (handle)
+ {
+ #if jin_thread == jin_thread_sdl
+ SDL_WaitThread(handle, nullptr);
+ #endif
+ }
+ #if jin_thread == jin_thread_sdl
+ handle = SDL_CreateThread(threadRunner, name.c_str(), p);
+ #elif jin_thread == jin_thread_cpp
+ handle = new std::thread();
+ #endif
+ return (running = (handle != nullptr));
+ }
+
+ void Thread::wait()
+ {
+ {
+ Lock l(mutex);
+ if (!handle)
+ return;
+ }
+ #if jin_thread == jin_thread_sdl
+ SDL_WaitThread(handle, nullptr);
+ #endif
+ Lock l(mutex);
+ running = false;
+ handle = nullptr;
+ }
+
+ void Thread::lock()
+ {
+ if (mutex != nullptr)
+ mutex->lock();
+ }
+
+ void Thread::unlock()
+ {
+ if (mutex != nullptr)
+ mutex->unlock();
+ }
+
+ void Thread::send(int slot, const Variant& value)
+ {
+ lock();
+ common->set(slot, value);
+ unlock();
+ condition->broadcast();
+ }
+
+ bool Thread::receive(int slot)
+ {
+ return common->exist(slot);
+ }
+
+ Thread::Variant Thread::fetch(int slot)
+ {
+ Thread::Variant v = common->get(slot);
+ return v;
+ }
+
+ Thread::Variant Thread::demand(int slot)
+ {
+ /**
+ * pthread_mutex_lock(mtx);
+ * while(pass == 0)
+ * {
+ * pthread_mutex_unlock(mtx);
+ * pthread_cond_just_wait(cv);
+ * pthread_mutex_lock(mtx);
+ * }
+ * pthread_mutex_unlock(mtx);
+ */
+ lock();
+ while (!common->exist(slot))
+ {
+ if (common->exist(ThreadData::SLOT_ERROR))
+ return 0;
+ condition->wait(mutex);
+ }
+ Thread::Variant v = common->get(slot);
+ unlock();
+ return v;
+ }
+
+ void Thread::remove(int slot)
+ {
+ lock();
+ common->remove(slot);
+ unlock();
+ }
+
+ } // namespace Threads
} // namespace JinEngine
#endif // defined(jin_thread) \ No newline at end of file
diff --git a/src/libjin/threads/thread.h b/src/libjin/threads/thread.h
index 2b7ee35..6319e38 100644
--- a/src/libjin/threads/thread.h
+++ b/src/libjin/threads/thread.h
@@ -6,160 +6,160 @@
#include <string>
#include <map>
#if jin_thread == jin_thread_sdl
- #include "SDL2/SDL_thread.h"
+ #include "SDL2/SDL_thread.h"
#elif jin_thread == jin_thread_cpp
- #include <thread>
- #include <mutex>
- #include <condition_variable>
+ #include <thread>
+ #include <mutex>
+ #include <condition_variable>
#endif
namespace JinEngine
{
- namespace Threads
- {
- /**
- * ӢӢMutual exclusionд Mutexһڶ̱߳Уֹ߳ͬʱͬһԴ
- * ȫֱждĻơĿͨƬһһٽcritical sectionɡٽ
- * ָһԹԴзʵĴ룬һֻƻ㷨һ򡢽̡߳̿ӵжٽ򣬵Dz
- * һӦûҪ˻ƵԴУꡢСжϴڶеĴ
- * ݡͬ״̬ȵԴάЩԴͬһºǺѵģΪһ߳̿κһʱ̱ͣ
- * ߣ߻ָѣ
- */
- class Mutex;
- class Conditional;
+ namespace Threads
+ {
+ /**
+ * ӢӢMutual exclusionд Mutexһڶ̱߳Уֹ߳ͬʱͬһԴ
+ * ȫֱждĻơĿͨƬһһٽcritical sectionɡٽ
+ * ָһԹԴзʵĴ룬һֻƻ㷨һ򡢽̡߳̿ӵжٽ򣬵Dz
+ * һӦûҪ˻ƵԴУꡢСжϴڶеĴ
+ * ݡͬ״̬ȵԴάЩԴͬһºǺѵģΪһ߳̿κһʱ̱ͣ
+ * ߣ߻ָѣ
+ */
+ class Mutex;
+ class Conditional;
- //
- // Thread::demand Receive a message from a thread. Wait for the message to exist before returning.
- // Thread::getName Get the name of a thread.
- // Thread::kill Forcefully terminate the thread.
- // Thread::peek Receive a message from a thread, but leave it in the message box.
- // Thread::receive Receive a message from a thread.
- // Thread::send Send a message.
- // Thread::set Set a value.
- // Thread::start Starts the thread.
- // Thread::wait Wait for a thread to finish.
- //
- class Thread
- {
- public:
- struct Variant
- {
- enum Type
- {
- NONE = 0,
- INTERGER,
- BOOLEAN,
- CHARACTER,
- CSTRING,
- POINTER,
- REAL,
- };
- Type type;
- union
- {
- int integer;
- bool boolean;
- char character;
- const char* cstring;
- void* pointer;
- float real;
- };
- Variant() :type(NONE) {};
- Variant(const Variant& v){ memcpy(this, &v, sizeof(v)); }
- Variant(int i) : integer(i), type(INTERGER) {};
- Variant(float f) : real(f), type(REAL) {};
- Variant(bool b) : boolean(b), type(BOOLEAN) {};
- Variant(char c) : character(c), type(CHARACTER) {};
- Variant(const char* s) : cstring(s), type(CSTRING) {};
- Variant(void* p) : pointer(p), type(POINTER) {};
- };
+ //
+ // Thread::demand Receive a message from a thread. Wait for the message to exist before returning.
+ // Thread::getName Get the name of a thread.
+ // Thread::kill Forcefully terminate the thread.
+ // Thread::peek Receive a message from a thread, but leave it in the message box.
+ // Thread::receive Receive a message from a thread.
+ // Thread::send Send a message.
+ // Thread::set Set a value.
+ // Thread::start Starts the thread.
+ // Thread::wait Wait for a thread to finish.
+ //
+ class Thread
+ {
+ public:
+ struct Variant
+ {
+ enum Type
+ {
+ NONE = 0,
+ INTERGER,
+ BOOLEAN,
+ CHARACTER,
+ CSTRING,
+ POINTER,
+ REAL,
+ };
+ Type type;
+ union
+ {
+ int integer;
+ bool boolean;
+ char character;
+ const char* cstring;
+ void* pointer;
+ float real;
+ };
+ Variant() :type(NONE) {};
+ Variant(const Variant& v){ memcpy(this, &v, sizeof(v)); }
+ Variant(int i) : integer(i), type(INTERGER) {};
+ Variant(float f) : real(f), type(REAL) {};
+ Variant(bool b) : boolean(b), type(BOOLEAN) {};
+ Variant(char c) : character(c), type(CHARACTER) {};
+ Variant(const char* s) : cstring(s), type(CSTRING) {};
+ Variant(void* p) : pointer(p), type(POINTER) {};
+ };
- private:
- class ThreadData
- {
- public:
- static const int SLOT_ERROR = -1;
- static const int SLOT_WARN = -2;
- static const int SLOT_INFO = -3;
- static const int SLOT_DEBUG = -4;
+ private:
+ class ThreadData
+ {
+ public:
+ static const int SLOT_ERROR = -1;
+ static const int SLOT_WARN = -2;
+ static const int SLOT_INFO = -3;
+ static const int SLOT_DEBUG = -4;
- ThreadData(Mutex*, Conditional*);
- ~ThreadData();
- bool exist(int slot);
- void set(int slot, Variant value);
- Variant get(int slot);
- void remove(int slot);
+ ThreadData(Mutex*, Conditional*);
+ ~ThreadData();
+ bool exist(int slot);
+ void set(int slot, Variant value);
+ Variant get(int slot);
+ void remove(int slot);
- Conditional* condition;
- Mutex* mutex;
+ Conditional* condition;
+ Mutex* mutex;
- private:
- std::map<int, Variant> share; // threads shared value
+ private:
+ std::map<int, Variant> share; // threads shared value
- };
+ };
- public:
- typedef int(*ThreadRunner)(void* obj);
+ public:
+ typedef int(*ThreadRunner)(void* obj);
- Thread(const std::string name, ThreadRunner threadfuncs);
- ~Thread();
- bool start(void* p);
- void wait();
- void send(int slot, const Variant& value);
- bool receive(int slot);
- Variant fetch(int slot);
- Variant demand(int slot);
- void remove(int slot);
- const char* getName();
- bool isRunning();
- void lock();
- void unlock();
+ Thread(const std::string name, ThreadRunner threadfuncs);
+ ~Thread();
+ bool start(void* p);
+ void wait();
+ void send(int slot, const Variant& value);
+ bool receive(int slot);
+ Variant fetch(int slot);
+ Variant demand(int slot);
+ void remove(int slot);
+ const char* getName();
+ bool isRunning();
+ void lock();
+ void unlock();
- protected:
- #if jin_thread == jin_thread_sdl
- SDL_Thread* handle; // SDL thread
- #elif jin_thread == jin_thread_cpp
- std::thread* handle; // cpp thread
- #endif
- Mutex* mutex; // mutex variable
- Conditional* condition; // condition variable
- ThreadRunner threadRunner; // thread function
- ThreadData* common; // threads common data
- const std::string name; // thread name, for debugging purposes
- /**
- * https://stackoverflow.com/questions/149932/naming-conventions-for-threads
- *
- * Use short names because they don't make the lines in a log file too long.
- *
- * Create names where the important part is at the beginning. Log viewers in a
- * graphical user interface tend to have tables with columns, and the thread
- * column is usually small or will be made small by you to read everything else.
- *
- * Do not use the word "thread" in the thread name because it is obvious.
- *
- * Make the thread names easily grep-able. Avoid similar sounding thread names
- *
- * If you have several threads of the same nature, enumerate them with IDs that
- * are unique to one execution of the application or one log file, whichever fits
- * your logging habits.
- *
- * Avoid generalizations like "WorkerThread" (how do you name the next 5 worker
- * threads?), "GUIThread" (which GUI? is it for one window? for everything?) or
- * "Calculation" (what does it calculate?).
- *
- * If you have a test group that uses thread names to grep your application's log
- * files, do not rename your threads after some time. Your testers will hate you for
- * doing so. Thread names in well-tested applications should be there to stay.
- *
- * When you have threads that service a network connection, try to include the target
- * network address in the thread name (e.g. channel_123.212.123.3). Don't forget about
- * enumeration though if there are multiple connections to the same host.
- */
- bool running; // running
+ protected:
+ #if jin_thread == jin_thread_sdl
+ SDL_Thread* handle; // SDL thread
+ #elif jin_thread == jin_thread_cpp
+ std::thread* handle; // cpp thread
+ #endif
+ Mutex* mutex; // mutex variable
+ Conditional* condition; // condition variable
+ ThreadRunner threadRunner; // thread function
+ ThreadData* common; // threads common data
+ const std::string name; // thread name, for debugging purposes
+ /**
+ * https://stackoverflow.com/questions/149932/naming-conventions-for-threads
+ *
+ * Use short names because they don't make the lines in a log file too long.
+ *
+ * Create names where the important part is at the beginning. Log viewers in a
+ * graphical user interface tend to have tables with columns, and the thread
+ * column is usually small or will be made small by you to read everything else.
+ *
+ * Do not use the word "thread" in the thread name because it is obvious.
+ *
+ * Make the thread names easily grep-able. Avoid similar sounding thread names
+ *
+ * If you have several threads of the same nature, enumerate them with IDs that
+ * are unique to one execution of the application or one log file, whichever fits
+ * your logging habits.
+ *
+ * Avoid generalizations like "WorkerThread" (how do you name the next 5 worker
+ * threads?), "GUIThread" (which GUI? is it for one window? for everything?) or
+ * "Calculation" (what does it calculate?).
+ *
+ * If you have a test group that uses thread names to grep your application's log
+ * files, do not rename your threads after some time. Your testers will hate you for
+ * doing so. Thread names in well-tested applications should be there to stay.
+ *
+ * When you have threads that service a network connection, try to include the target
+ * network address in the thread name (e.g. channel_123.212.123.3). Don't forget about
+ * enumeration though if there are multiple connections to the same host.
+ */
+ bool running; // running
- };
+ };
- } // namespace Threads
+ } // namespace Threads
} // namespace JinEngine
#endif // defined(jin_thread)