From d5e1e1f47ef2144ab730ada87809a71adfcecade Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Wed, 30 Aug 2017 21:16:40 +0200 Subject: [PATCH] [DEV] start add thread --- ethread/Mutex.Windows.cpp | 29 ++++++++++++ ethread/Mutex.h | 75 ++++++++++++++++++++++++++++++ ethread/Mutex.pthread.cpp | 38 +++++++++++++++ ethread/Semaphore.Windows.cpp | 46 ++++++++++++++++++ ethread/Semaphore.h | 65 ++++++++++++++++++++++++++ ethread/Semaphore.pthread.cpp | 87 +++++++++++++++++++++++++++++++++++ ethread/Thread.hpp | 42 +++++++++++++++++ ethread/Thread.pthread.cpp | 0 lutin_ethread.py | 18 +++++++- 9 files changed, 399 insertions(+), 1 deletion(-) create mode 100644 ethread/Mutex.Windows.cpp create mode 100644 ethread/Mutex.h create mode 100644 ethread/Mutex.pthread.cpp create mode 100644 ethread/Semaphore.Windows.cpp create mode 100644 ethread/Semaphore.h create mode 100644 ethread/Semaphore.pthread.cpp create mode 100644 ethread/Thread.hpp create mode 100644 ethread/Thread.pthread.cpp diff --git a/ethread/Mutex.Windows.cpp b/ethread/Mutex.Windows.cpp new file mode 100644 index 0000000..345be76 --- /dev/null +++ b/ethread/Mutex.Windows.cpp @@ -0,0 +1,29 @@ +/** + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + + +#include + +ethread::Mutex::Mutex() { + InitializeCriticalSection(&m_mutex); +} + +ethread::Mutex::~Mutex() { + DeleteCriticalSection(&m_mutex); +} + +void ethread::Mutex::lock() { + EnterCriticalSection(&m_mutex); +} + +bool ethread::Mutex::tryLock() { + return TryEnterCriticalSection(&m_mutex) != 0; +} + +void ethread::Mutex::unLock() { + LeaveCriticalSection(&m_mutex); +} + diff --git a/ethread/Mutex.h b/ethread/Mutex.h new file mode 100644 index 0000000..6f7c137 --- /dev/null +++ b/ethread/Mutex.h @@ -0,0 +1,75 @@ +/** + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once +#include + +#ifdef __TARGET_OS__Windows + #include +#else + #include +#endif + +namespace ethread { + /** + * @brief Generic mutex interface (OS independent) + */ + class Mutex { + private: + #ifdef __TARGET_OS__Windows + CRITICAL_SECTION m_mutex; + #else + pthread_mutex_t m_mutex; + #endif + public: + /** + * @brief Create a new mutex + */ + Mutex(); + /** + * @brief Destroy the mutex. + */ + ~Mutex(); + /** + * @brief Lock the mutex (Wait while the mutex is not lock) + */ + void lock(); + /** + * @brief Try to lock the mutex (exit if mutex is already locked) + * @return true The mutex is locked + * @return false The mutex is already locked. + */ + bool tryLock(); + /** + * @brief Unloc the mutex + */ + void unLock(); + }; + /** + * @brief AutoLock and un-lock when exit fuction. + */ + class uniqueLock { + private: + // Keep a reference on the mutex + ethread::Mutex &m_protect; + public: + /** + * @brief constructor that automaticly lock the mutex. + * @param[in] _protect Mutex to Lock. + */ + uniqueLock(ethread::Mutex& _protect) : + m_protect(_protect) { + m_protect.lock(); + } + /** + * @brief Destructor that Auto Unlock mutex when remove. + */ + virtual ~uniqueLock(){ + m_protect.unLock(); + } + }; +}; + +#endif diff --git a/ethread/Mutex.pthread.cpp b/ethread/Mutex.pthread.cpp new file mode 100644 index 0000000..7ef761f --- /dev/null +++ b/ethread/Mutex.pthread.cpp @@ -0,0 +1,38 @@ +/** + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include + +ethread::Mutex::Mutex() { + // create interface mutex : + int ret = pthread_mutex_init(&m_mutex, nullptr); + ETHREAD_ASSERT(ret == 0, "Error creating Mutex ..."); +} + + +ethread::Mutex::~Mutex() { + // Remove mutex + int ret = pthread_mutex_destroy(&m_mutex); + ETHREAD_ASSERT(ret == 0, "Error destroying Mutex ..."); +} + + +void ethread::Mutex::lock() { + pthread_mutex_lock(&m_mutex); +} + + +bool ethread::Mutex::tryLock() { + return pthread_mutex_trylock(&m_mutex) != 0; +} + + +void ethread::Mutex::unLock() { + pthread_mutex_unlock(&m_mutex); +} + diff --git a/ethread/Semaphore.Windows.cpp b/ethread/Semaphore.Windows.cpp new file mode 100644 index 0000000..995792c --- /dev/null +++ b/ethread/Semaphore.Windows.cpp @@ -0,0 +1,46 @@ +/** + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#include +#include +#include + +etk::Semaphore::Semaphore(uint32_t _nbBasicElement, uint32_t _nbMessageMax) { + // create interface mutex : + m_semaphore = CreateSemaphore(nullptr, _nbBasicElement, _nbMessageMax, nullptr); + TK_ASSERT(m_semaphore != 0, "Error creating SEMAPHORE ..."); +} + + +etk::Semaphore::~Semaphore() { + CloseHandle(m_semaphore); +} + +uint32_t etk::Semaphore::getCount() { + LONG tmpData = 0; + ReleaseSemaphore(m_semaphore, 0, &tmpData); + return tmpData; +} + +void etk::Semaphore::post() { + ReleaseSemaphore(m_semaphore, 1, nullptr); +} + + +void etk::Semaphore::wait() { + WaitForSingleObject(m_semaphore, INFINITE); +} + + +bool etk::Semaphore::wait(uint64_t _timeOutInUs) { + DWORD result = WaitForSingleObject(m_semaphore, _timeOutInUs); + if (result == WAIT_FAILED) { + TK_ERROR("Failed to wait for semaphore "); + return false; + } else { + return result == WAIT_OBJECT_0; + } +} + diff --git a/ethread/Semaphore.h b/ethread/Semaphore.h new file mode 100644 index 0000000..027d0ab --- /dev/null +++ b/ethread/Semaphore.h @@ -0,0 +1,65 @@ +/** + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include + +#ifdef __TARGET_OS__Windows + #include +#else + #include +#endif + +namespace ethread { + /** + * @brief Generic semaphore wrapper ( it is os independent) + */ + class Semaphore { + private: + #ifdef __TARGET_OS__Windows + HANDLE m_semaphore; + #else + pthread_mutex_t m_mutex; + pthread_cond_t m_condition; + uint32_t m_data; + uint32_t m_maximum; + #endif + public: + /** + * @brief Contruct the inithialized semaphore. + * @param[in] _nbBasicElement Number of element basicly set in the semaphore list + * @param[in] _nbMessageMax Nunber of maximun message that can be set. + */ + Semaphore(uint32_t _nbBasicElement=0, uint32_t _nbMessageMax=1); + /** + * @brief Generic destructor. + */ + ~Semaphore(); + /** + * @brief Get the number of element in the semaphore. + * @return Number of stored elements. + */ + uint32_t getCount(); + /** + * @brief Post a new semaphore + */ + void post(); + /** + * @brief Wait for a new semaphore post by an other thread. + */ + void wait(); + /** + * @brief Wait for a new semaphore post by an other thread, + * with a timeout in micro-second. + * @param[in] _timeOutInUs Number of micro-second to wait a semaphore. + * @return true The function get a semaphore. + * @return false The time-out appear or an error occured. + */ + bool wait(uint64_t _timeOutInUs); + }; +}; + +#endif diff --git a/ethread/Semaphore.pthread.cpp b/ethread/Semaphore.pthread.cpp new file mode 100644 index 0000000..07b7afe --- /dev/null +++ b/ethread/Semaphore.pthread.cpp @@ -0,0 +1,87 @@ +/** + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#include +#include +#include +#include + +ethread::Semaphore::Semaphore(uint32_t _nbBasicElement, uint32_t _nbMessageMax) { + // create interface mutex : + int ret = pthread_mutex_init(&m_mutex, nullptr); + TK_ASSERT(ret == 0, "Error creating Mutex ..."); + // create contition : + ret = pthread_cond_init(&m_condition, nullptr); + TK_ASSERT(ret == 0, "Error creating Condition ..."); + if (ret != 0) { + ret = pthread_mutex_destroy(&m_mutex); + TK_ASSERT(ret == 0, "Error destroying Mutex ..."); + } + m_maximum = _nbMessageMax; + m_data = _nbBasicElement; +} + + +ethread::Semaphore::~Semaphore() { + // Remove condition + int ret = pthread_cond_destroy(&m_condition); + TK_ASSERT(ret == 0, "Error destroying Condition ..."); + // Remove Mutex + ret = pthread_mutex_destroy(&m_mutex); + TK_ASSERT(ret == 0, "Error destroying Mutex ..."); +} + +uint32_t ethread::Semaphore::getCount() { + int32_t tmpData = 0; + pthread_mutex_lock(&m_mutex); + tmpData = m_data; + pthread_mutex_unlock(&m_mutex); + return tmpData; +} + +void ethread::Semaphore::post() { + pthread_mutex_lock(&m_mutex); + if (m_data>=m_maximum) { + m_data = m_maximum; + } else { + m_data++; + } + // send message + pthread_cond_broadcast(&m_condition); + pthread_mutex_unlock(&m_mutex); +} + + +void ethread::Semaphore::wait() { + pthread_mutex_lock(&m_mutex); + while(m_data == 0) { + pthread_cond_wait(&m_condition, &m_mutex); + } + m_data--; + pthread_mutex_unlock(&m_mutex); +} + + +bool ethread::Semaphore::wait(uint64_t _timeOutInUs) { + pthread_mutex_lock(&m_mutex); + if(m_data == 0) { + struct timeval tp; + struct timespec ts; + gettimeofday(&tp, nullptr); + uint64_t totalTimeUS = tp.tv_sec * 1000000 + tp.tv_usec; + totalTimeUS += _timeOutInUs; + ts.tv_sec = totalTimeUS / 1000000; + ts.tv_nsec = (totalTimeUS%1000000) * 1000; + int ret = pthread_cond_timedwait(&m_condition, &m_mutex, &ts); + if (ret !=0) { //== ETIMEOUT) { + pthread_mutex_unlock(&m_mutex); + return false; + } + } + m_data--; + pthread_mutex_unlock(&m_mutex); + return true; +} + diff --git a/ethread/Thread.hpp b/ethread/Thread.hpp new file mode 100644 index 0000000..19820bb --- /dev/null +++ b/ethread/Thread.hpp @@ -0,0 +1,42 @@ +/** + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once +#include +#include +#include + +#ifdef __TARGET_OS__Windows + #error TODO ... +#else + #include +#endif + +namespace ethread { + /** + * @brief Generic Thread interface (OS independent) + */ + class Thread { + private: + #ifdef __TARGET_OS__Windows + + #else + pthread_mutex_t m_thread; + #endif + uint32_t m_uid; //!< unique id of the thread + etk::String m_name; //!< Name of the thread (do not get it on the system ==> more portable) + etk::Function m_function; //!< Function to call every cycle of the thead running + public: + Thread(etk::Function&& _call, const std::string& _name); + ~Thread(); + void join(); + bool detach(); + void setName(const std::string& _name); + const std::string& setName() const; + uint32_t getIdentifier() const; + }; +} + +#endif diff --git a/ethread/Thread.pthread.cpp b/ethread/Thread.pthread.cpp new file mode 100644 index 0000000..e69de29 diff --git a/lutin_ethread.py b/lutin_ethread.py index 1017b9d..01d92bd 100644 --- a/lutin_ethread.py +++ b/lutin_ethread.py @@ -42,13 +42,29 @@ def configure(target, my_module): 'ethread/Pool.hpp', 'ethread/PoolAction.hpp', 'ethread/PoolExecutor.hpp', + 'ethread/Mutex.hpp', + 'ethread/Semaphore.hpp', + 'ethread/Thread.hpp', ]) + if "Windows" in target.get_type(): + my_module.add_src_file([ + 'ethread/Mutex.Windows.cpp', + 'ethread/Semaphore.Windows.cpp', + 'ethread/Thread.Windows.cpp', + ]) + else: + my_module.add_src_file([ + 'ethread/Mutex.pthread.cpp', + 'ethread/Semaphore.pthread.cpp', + 'ethread/Thread.pthread.cpp', + my_module.add_depend([ + 'pthread', + ]) # build in C++ mode my_module.compile_version("c++", 2011) # add dependency of the generic C++ library: my_module.add_depend([ - 'cxx', 'elog', 'etk', 'ethread-tools',