diff options
Diffstat (limited to 'src/libjin/threads/je_thread.h')
-rw-r--r-- | src/libjin/threads/je_thread.h | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/src/libjin/threads/je_thread.h b/src/libjin/threads/je_thread.h new file mode 100644 index 0000000..77f147d --- /dev/null +++ b/src/libjin/threads/je_thread.h @@ -0,0 +1,167 @@ +#ifndef __JE_THREAD_H__ +#define __JE_THREAD_H__ +#include "../core/je_configuration.h" +#if defined(jin_thread) + +#include <string> +#include <map> +#if jin_thread == jin_thread_sdl + #include "SDL2/SDL_thread.h" +#elif jin_thread == jin_thread_cpp + #include <thread> + #include <mutex> + #include <condition_variable> +#endif + +namespace JinEngine +{ + 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) {}; + }; + + 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); + + Conditional* condition; + Mutex* mutex; + + private: + std::map<int, Variant> share; // threads shared value + + }; + + 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(); + + 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 JinEngine + +#endif // defined(jin_thread) + +#endif // __JE_THREAD_H__
\ No newline at end of file |