From: <mik...@us...> - 2003-12-24 11:52:52
|
Update of /cvsroot/sharedaemon/sharedaemon-ui-web/src/thread In directory sc8-pr-cvs1:/tmp/cvs-serv22602/src/thread Added Files: Mutex.h Mutex.cpp Condition.cpp Condition.h Log Message: 24/12/2003 Barbeaux * Implemented Mutex and Condition. * Implemented a ThreadException. * Added origin message into Exception handler. --- NEW FILE: Mutex.h --- /* * This file is part of webInterface. * Copyright (C) 2003 Mikael Barbeaux <mik...@us...> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MUTEX_H_ #define _MUTEX_H_ #ifdef _WIN32_ #include <windows.h> // Use HANDLE as the pthread_mutex_t type typedef HANDLE pthread_mutex_t; #else #include <pthread.h> #include <sys/errno.h> #endif #include "../exceptions/ThreadException.h" /** * Defines a mutex handler. * A mutex is a synchronizer between mutliple * threads. It allows to define a part of code that * will be executed by only one thread at each time. */ class Mutex { protected: // the mutex pthread_mutex_t *mutex; public: /** * Creates a Mutex object. */ Mutex() throw (ThreadException); /** * Destroys a Mutex object. */ ~Mutex(); /** * Locks the mutex. */ void lock() throw (ThreadException); /** * Tries to enter the mutex without any wait. * * @return bool */ bool tryLock() throw (ThreadException); /** * Unlocks the mutex. */ void unlock() throw (ThreadException); }; #endif --- NEW FILE: Mutex.cpp --- /* * This file is part of webInterface. * Copyright (C) 2003 Mikael Barbeaux <mik...@us...> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "Mutex.h" /** * Creates the Mutex object, by * allocating and initializing the * mutex parameter. */ Mutex::Mutex() throw (ThreadException) { // Allocate mutex mutex = new pthread_mutex_t; if(mutex == 0) throw ThreadException(MutexError, "Cannot allocate the mutex.", "Mutex::Mutex"); // Initialize the mutex #ifdef _WIN32_ if((*mutex = ::CreateMutex(0,0,0)) == 0) throw ThreadException(MutexError, "Cannot create the mutex", "Mutex::Mutex"); #else if(::pthread_mutex_init(mutex, 0)) throw ThreadException(MutexError, "Cannot create the mutex", "Mutex::Mutex"); #endif } /** * Destructs a Mutex object. * Before destroying it, we need to be sure * that the mutex is unlocked. */ Mutex::~Mutex() { // Waits for the mutex to unlock #ifdef _WIN32_ while(::CloseHandle(*mutex) == 0) { lock(); unlock(); } #else while(::pthread_mutex_destroy(mutex) == EBUSY) { lock(); unlock(); } #endif // delete the mutex delete mutex; mutex = 0; } /** * Locks the mutex. */ void Mutex::lock() throw (ThreadException) { // Locking the mutex #ifdef _WIN32_ // waits indefinitively for the mutex... if(::WaitForSingleObject(*mutex, INFINITE) != WAIT_OBJECT_0) throw ThreadException(MutexError, "Cannot lock the mutex.", "Mutex::lock"); #else if(::pthread_mutex_lock(mutex) != 0) throw ThreadException(MutexError, "Cannot lock the mutex.", "Mutex::lock"); #endif } /** * Tries to lock the mutex. * Returns false if the mutex is already ownded by another * thread. */ bool Mutex::tryLock() throw (ThreadException) { /** * Waits 0 second for the mutex, * if it returns a TIMEOUT, then the mutex is * already owned. */ #ifdef _WIN32_ int ret = ::WaitForSingleObject(*mutex, 0); if(ret == WAIT_TIMEOUT) return false; else if(ret != WAIT_OBJECT_0) throw ThreadException(MutexError, "Cannot tryLock the mutex.", "Mutex::tryLock"); return true; #else int ret = ::pthread_mutex_trylock(mutex); if(ret == EBUSY) return false; else if(ret != 0) throw ThreadException(MutexError, "Cannot tryLock the mutex", "Mutex::tryLock"); return true; #endif } /** * Unlocks the mutex. */ void Mutex::unlock() throw (ThreadException) { // Unlocking the mutex... #ifdef _WIN32_ if(::ReleaseMutex(*mutex) == 0) throw ThreadException(MutexError, "Cannot unlock the mutex.", "Mutex::unlock"); #else if(::pthread_mutex_unlock(mutex) != 0) throw ThreadException(MutexError, "Cannot unlock the mutex.", "Mutex::unlock"); #endif } --- NEW FILE: Condition.cpp --- /* * This file is part of webInterface. * Copyright (C) 2003 Mikael Barbeaux <mik...@us...> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "Condition.h" /** * Creates a Condition object. * Allocates the condition object and initializes it. */ Condition::Condition() throw (ThreadException){ condition = new pthread_cond_t; if(condition == 0) throw ThreadException(ConditionError, "Cannot allocate the condition.", "Condition::Condition"); #ifdef _WIN32_ // Init struct parameters condition->nb_waiting = 0; condition->broadcast = false; ::InitializeCriticalSection(&(condition->waiting_lock)); condition->semaphore = ::CreateSemaphore(0, 0, 0x7fffffff, 0); condition->waiters_done = ::CreateEvent(0,false,false,0); /* If semaphore or waiters_done are nulls, can't create condition. */ if((condition->semaphore == 0) || (condition->waiters_done == 0)) throw ThreadException(ConditionError, "Cannot create the condition.", "Condition::Condition"); #else // init pthread condition if(::pthread_cond_init(condition, 0) != 0) throw ThreadException(ConditionError, "Cannot create the condition.", "Condition::Condition"); #endif } /** * Condition destructor * For win32 users, it deletes all data in the condition * structure. Then, it destroys the condition object. */ Condition::~Condition() { // Destroys the condition content #ifdef _WIN32_ ::DeleteCriticalSection(&(condition->waiting_lock)); /* While there are threads waiting for the condition, send the broadcast message to release them. */ while(::CloseHandle(condition->semaphore) == 0) sendBroadcastSignal(); while(::CloseHandle(condition->waiters_done) == 0) sendBroadcastSignal(); #else while(::pthread_cond_destroy(condition) == EBUSY) sendBroadcastSignal(); #endif //Delete the condition delete condition; condition = 0; } /** * Waits for a signal to release the condition. * Called when a new thread is added to the waiting threads * for the condition. */ void Condition::waitForSignal() throw (ThreadException) { #ifdef _WIN32_ // Adds a new waiting thread EnterCriticalSection(&(condition->waiting_lock)); ++(condition->nb_waiting); LeaveCriticalSection(&(condition->waiting_lock)); /* Waits indefinitively for the semaphore to release the mutex. */ HANDLE *mutex_t = (HANDLE*) mutex; if(::SignalObjectAndWait(*mutex_t, condition->semaphore, INFINITE, false) != WAIT_OBJECT_0) { // semaphore is invalid unlock(); throw ThreadException(ConditionError, "Invalid semaphore.", "Condition::waitforSignal"); } // Waiting time is finished, we leave the waiting area EnterCriticalSection(&(condition->waiting_lock)); --(condition->nb_waiting); // Are we the last waiter of a broadcast message ? bool last_waiter = (condition->broadcast && (condition->nb_waiting == 0)); LeaveCriticalSection(&(condition->waiting_lock)); if(last_waiter) { // Wait for all waiting threads to leave the mutex. if(::SignalObjectAndWait(condition->waiters_done, *mutex_t, INFINITE, false) != WAIT_OBJECT_0) { // the mutex is invalid unlock(); throw ThreadException(ConditionError, "Invalid mutex.", "Condition::waitForSignal"); } } /* if not last waiter of broadcast message, just wait for a single message on the mutex. */ else if(::WaitForSingleObject(*mutex_t, INFINITE) != WAIT_OBJECT_0) { unlock(); throw ThreadException(ConditionError, "Invalid mutex.", "Condition::waitForSignal"); } #else if(::pthread_cond_wait(condition, mutex) != 0) { unlock(); throw ThreadException(ConditionError, "Invalid condition.", "Condition::waitForSignal"); } #endif } /** * Sends a signal to the condition in order to release * a unique waiting thread. */ void Condition::sendSignal()throw (ThreadException) { #ifdef _WIN32_ // We retrieve first the number of waiting threads EnterCriticalSection(&(condition->waiting_lock)); int nb_waiting = condition->nb_waiting; LeaveCriticalSection(&(condition->waiting_lock)); // Release a unique thread if any are waiting if((nb_waiting > 0) && (::ReleaseSemaphore(condition->semaphore,1,0) == 0)) { // if the condition is invalid unlock(); throw ThreadException(ConditionError, "Invalid condition.", "Condition::sendSignal"); } #else if(::pthread_cond_signal(condition) != 0) { unlock(); throw ThreadException(ConditionError, "Invalid condition", "Condition::sendSignal"); } #endif } /** * Sends a signal to the condition in order to release * every waiting threads. */ void Condition::sendBroadcastSignal()throw (ThreadException) { #ifdef _WIN32_ EnterCriticalSection(&(condition->waiting_lock)); // If there are waiting threads if(condition->nb_waiting > 0) { condition->broadcast = true; // Release all waiting threads if(! ::ReleaseSemaphore(condition->semaphore, condition->nb_waiting, 0)) { // Can't release the semaphore unlock(); throw ThreadException(ConditionError, "Cannot release the semaphore.", "Condition::sendBroadcastSignal"); } LeaveCriticalSection(&(condition->waiting_lock)); // waits for the thread to acquire the semaphore if(::WaitForSingleObject(condition->waiters_done, INFINITE) != WAIT_OBJECT_0) { unlock(); throw ThreadException(ConditionError, "Invalid event.", "Condition::sendBroadcastSignal"); } condition->broadcast = false; } else LeaveCriticalSection(&(condition->waiting_lock)); #else if(::pthread_cond_broadcast(condition) != 0) { unlock(); throw ThreadException(ConditionError, "Invalid condition.", "Condition::sendBroadcastSignal"); } #endif } --- NEW FILE: Condition.h --- /* * This file is part of webInterface. * Copyright (C) 2003 Mikael Barbeaux <mik...@us...> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _CONDITION_H #define _CONDITION_H #include "Mutex.h" #include "../exceptions/ThreadException.h" #ifdef _WIN32_ /** * For windows users, there isn't such a * pthread_cond_t object to handle. * Thanks to Marc Parizeau for his help and * D.C. Schmidt and Irfan Pyarali for their * pthread_cond_t implementation. */ #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0400 #endif #include <windows.h> typedef struct { // Number of threads waiting for the condition int nb_waiting; // is it a broadcast signal ? bool broadcast; // A critical section for protecting nb_waiting CRITICAL_SECTION waiting_lock; /* A semaphore, used for queueing up waiting threads for condition */ HANDLE semaphore; /* An auto reset event used by the broadcast signal thread to wait for all the waiting threads to wake up */ HANDLE waiters_done; } pthread_cond_t; #else #include <pthread.h> #include <sys/errno.h> #endif /** * Defines a Condition object. * A condition is a mutex that is released when * another thread sends a signal to the condition. All * waiting threads can be released whe the signal sent * is a broadcast signal, or just one of them if * the signal is simple. */ class Condition : public Mutex { protected: // the condition pthread_cond_t *condition; public: /** * Creates a Condition object. */ Condition() throw (ThreadException); /** * Condition destructor */ ~Condition(); /** * Waits for a signal to be sent to the condition. */ void waitForSignal() throw (ThreadException); /** * Sends a simple signal to the condition. */ void sendSignal() throw (ThreadException); /** * Sends a broadcast signal to the condition. */ void sendBroadcastSignal() throw (ThreadException); }; #endif |