diff options
Diffstat (limited to 'src/MTS_Thread.cpp')
-rw-r--r-- | src/MTS_Thread.cpp | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/src/MTS_Thread.cpp b/src/MTS_Thread.cpp new file mode 100644 index 0000000..3537731 --- /dev/null +++ b/src/MTS_Thread.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2015 by Multi-Tech Systems + * + * This file is part of libmts. + * + * libmts is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * libmts is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libmts. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <mts/MTS_Thread.h> +#include <mts/MTS_Logger.h> +#include <new> +#include <cassert> + +using namespace MTS; + +Thread::Thread(const std::string& name, bool managed) +: m_pThread(NULL) +, m_sName(name) +, m_bManaged(managed) +, m_bComplete(true) +, m_bCanceled(true) +{ + printConfig("Thread| %s()", getName().c_str()); + m_apThreadLock.reset(new Lock()); + m_apStateLock.reset(new Lock()); + m_apCompleteCondition.reset(m_apStateLock->createCondition()); +} + +Thread::~Thread() { + m_bCanceled = true; + Thread::stop(); + m_apCompleteCondition.reset(); + m_apStateLock.reset(); + m_apThreadLock.reset(); + printConfig("Thread| %s - deconstructed", getName().c_str()); +} + +void Thread::sleep(uint32_t millis) { +#ifdef WIN32 + Sleep(millis); +#else + Lock lock; + Condition* condition = lock.createCondition(); + lock.lock(); + condition->wait(millis); + lock.unlock(); + delete condition; +#endif +} + +const std::string& Thread::getName() const { + return m_sName; +} + +void Thread::start() { + m_apThreadLock->lock(); + try { + if (m_pThread == NULL) { + reset(); +#ifdef WIN32 + m_pThread = CreateThread(NULL, 0, &doInBackground, this, 0, NULL); +#else + m_pThread = new (std::nothrow) pthread_t; + if (m_pThread != NULL) { + const int result = pthread_create(m_pThread, NULL, + &doInBackground, this); + assert(result == 0); + if (result != 0) { + delete m_pThread; + m_pThread = NULL; + } + } + +#endif + assert(m_pThread != NULL); + if (m_pThread != NULL) { + printConfig("Thread| %s - started (%p)", + getName().c_str(), m_pThread); + } else { + printWarning("Thread| Failed to start runnable %s", + getName().c_str()); + m_apStateLock->lock(); + m_bCanceled = true; + m_bComplete = true; + m_apStateLock->unlock(); + } + } + } catch (...) { + printWarning("Thread| Failed to start runnable %s", getName().c_str()); + assert(false); + } + m_apThreadLock->unlock(); +} + +void Thread::stop() { + m_apThreadLock->lock(); + cancel(); + if (m_pThread != NULL) { + wait(1500); + +#ifdef WIN32 + if (!isDone()) { + TerminateThread(m_pThread, 1); + printConfig("Thread| %s - terminated", getName().c_str()); + } + const BOOL ok = CloseHandle(m_pThread); + assert(ok); +#else + if (!isDone()) { + printConfig("Thread| %s - terminated", getName().c_str()); + } + delete m_pThread; +#endif + m_pThread = NULL; + } else if (!isDone()) { + done(); + } + m_apThreadLock->unlock(); +} + +void Thread::wait() { + m_apStateLock->lock(); + if (!m_bComplete) { + m_apCompleteCondition->wait(); + } + m_apStateLock->unlock(); +} + +void Thread::wait(uint32_t millis) { + m_apStateLock->lock(); + if (!m_bComplete) { + m_apCompleteCondition->wait(millis); + } + m_apStateLock->unlock(); +} + +bool Thread::isAlive() const { + bool result = false; + m_apThreadLock->lock(); + result = (m_pThread != NULL); + m_apThreadLock->unlock(); + return result; +} + +bool Thread::isCanceled() const { + bool result = false; + m_apStateLock->lock(); + result = m_bCanceled; + m_apStateLock->unlock(); + return result; +} + +void Thread::cancel() { + m_apStateLock->lock(); + if (!m_bCanceled) { + m_bCanceled = true; + printConfig("Thread| %s - cancelled", getName().c_str()); + } + m_apStateLock->unlock(); +} + +bool Thread::isDone() const { + bool result = false; + m_apStateLock->lock(); + result = m_bComplete; + m_apStateLock->unlock(); + return result; +} + +void Thread::done() { + m_apStateLock->lock(); + m_bComplete = true; + m_apCompleteCondition->signal(); + printConfig("Thread| %s - done", getName().c_str()); + m_apStateLock->unlock(); +} + +void Thread::reset() { + m_apStateLock->lock(); + m_bCanceled = false; + m_bComplete = false; + m_apStateLock->unlock(); +} + +bool Thread::isManaged() const { + return m_bManaged; +} + +#ifdef WIN32 +DWORD WINAPI Thread::doInBackground(__in LPVOID parameter) { +#else +void* Thread::doInBackground(void* parameter) { +#endif + + Thread* runnable = static_cast<Thread*>(parameter); + assert(runnable != NULL); + if (runnable != NULL) { + printConfig("Thread| %s - initializing\n", runnable->getName().c_str()); + try { + runnable->run(); + } catch (...) { + printWarning("Thread| exception caught while running %s", + runnable->getName().c_str()); + } + printConfig("Thread| %s - finalizing", runnable->getName().c_str()); + bool managed = runnable->isManaged(); + runnable->done(); + if (!managed) { + printConfig("Thread| %s - deleted", runnable->getName().c_str()); + delete runnable; + } + } + return 0; +} + |