/* * 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 . * */ #include #include #include #include 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(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; }