itom 1.0.14
|
00001 /* ******************************************************************** 00002 itom software 00003 URL: http://www.uni-stuttgart.de/ito 00004 Copyright (C) 2013, Institut für Technische Optik (ITO), 00005 Universität Stuttgart, Germany 00006 00007 This file is part of itom and its software development toolkit (SDK). 00008 00009 itom is free software; you can redistribute it and/or modify it 00010 under the terms of the GNU Library General Public Licence as published by 00011 the Free Software Foundation; either version 2 of the Licence, or (at 00012 your option) any later version. 00013 00014 In addition, as a special exception, the Institut für Technische 00015 Optik (ITO) gives you certain additional rights. 00016 These rights are described in the ITO LGPL Exception version 1.0, 00017 which can be found in the file LGPL_EXCEPTION.txt in this package. 00018 00019 itom is distributed in the hope that it will be useful, but 00020 WITHOUT ANY WARRANTY; without even the implied warranty of 00021 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library 00022 General Public Licence for more details. 00023 00024 You should have received a copy of the GNU Library General Public License 00025 along with itom. If not, see <http://www.gnu.org/licenses/>. 00026 *********************************************************************** */ 00027 00028 #ifndef SHAREDSTRUCTURES_QT_H 00029 #define SHAREDSTRUCTURES_QT_H 00030 00031 #include <qmutex.h> 00032 #include <qsemaphore.h> 00033 #include <qdebug.h> 00034 #include <qeventloop.h> 00035 00036 #include "sharedStructures.h" 00037 00038 00039 class ItomSharedSemaphore 00040 { 00041 private: 00042 QSemaphore *m_pSemaphore; 00043 int m_instCounter; 00044 bool m_enableDelete; 00045 int m_numOfListeners; 00046 bool m_callerStillWaiting; 00047 QMutex internalMutex; 00049 public: 00051 00059 inline ItomSharedSemaphore(int numberOfListeners = 1) : m_numOfListeners(numberOfListeners), m_instCounter(numberOfListeners + 1), m_enableDelete(false), m_callerStillWaiting(true), returnValue(ito::retOk) 00060 { 00061 internalMutex.lock(); 00062 m_pSemaphore = new QSemaphore(m_numOfListeners); 00063 m_pSemaphore->acquire(m_numOfListeners); 00064 internalMutex.unlock(); 00065 } 00066 00068 /* 00069 \sa ItomSharedSemaphore::deleteSemaphore 00070 */ 00071 inline ~ItomSharedSemaphore() 00072 { 00073 Q_ASSERT_X(m_enableDelete, "~ItomSharedSemaphore", "it is not allowed to directly destroy ItomSharedSemaphore. Always use ItomSharedSemaphore::deleteSemaphore(...)"); 00074 00075 if(m_pSemaphore->available() < m_numOfListeners) 00076 { 00077 m_pSemaphore->release( m_numOfListeners - m_pSemaphore->available()); 00078 qDebug("ItomSharedSemaphore is not fully available at moment of destruction"); 00079 } 00080 delete m_pSemaphore; 00081 m_pSemaphore = NULL; 00082 } 00083 00085 /* 00086 The timeout time is indicated in milliseconds, a value equal to -1 means that no timeout is set and this methods 00087 only returns if the called method released the semaphore. In the constructor of ItomSharedSemaphore, the semaphore 00088 has been locked with a number equal to the number of listeners, which usually is 1. The semaphore is unlocked, if 00089 every listener releases the semaphore once (\sa release). 00090 00091 A possible timeout is indicated by a debug-warning in the output window of the IDE. 00092 00093 @param [in] timeout in ms [-1 : no timeout] 00094 @return true if caller (listener) released the lock within the given timeout time, false if timeout expired 00095 @sa release, waitAndProcessEvents 00096 */ 00097 inline bool wait(int timeout) 00098 { 00099 bool temp; 00100 temp = m_pSemaphore->tryAcquire(m_numOfListeners, timeout); 00101 00102 QMutexLocker mutexLocker(&internalMutex); 00103 if(temp == false) 00104 { 00105 qDebug() << "ItomSharedSemaphore run into a timeout. Number of attempted listeners: " << m_numOfListeners << ", already freed: " << m_pSemaphore->available(); 00106 } 00107 else 00108 { 00109 m_pSemaphore->release(m_numOfListeners); 00110 } 00111 00112 m_callerStillWaiting = false; 00113 00114 return temp; 00115 } 00116 00117 bool waitAndProcessEvents(int timeout, QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents); 00118 00120 /* 00121 the called method in another thread must release the semaphore as soon as possible such that the caller can continue 00122 */ 00123 inline void release() { /*qDebug() << "semaphore release";*/ m_pSemaphore->release(1); } 00124 00126 /* 00127 @return true if semaphore is still locked, else false 00128 */ 00129 inline int available() const { return m_pSemaphore->available(); } 00130 00132 /* 00133 this method is not 100% thread-safe, that means it might occure, that the wait-method of the caller drops into the timeout 00134 during the call to the method isCallerStillWaiting. Therefore consider this method as pure information. 00135 00136 @return true if caller-method is still waiting (in \sa wait-method) that all listeners are calling the release method 00137 in order to free the lock of the semaphore. else: false 00138 */ 00139 inline bool isCallerStillWaiting() { QMutexLocker mutexLocker(&internalMutex); return m_callerStillWaiting; } 00140 00142 // 00143 // Every listener and the caller-method must call this static method with the pointer to the corresponding ItomSharedSemaphore 00144 // in order to guarantee the final deletion of the semaphore, if it is not needed any more by any participating method (caller or listener). 00145 // 00146 // In every listener method (called method) you should call this method after you released the semaphore (\sa release). 00147 // The ItomSharedSemaphore consists of a internal reference counter, which is set to the number of listeners plus 1 at 00148 // construction time. Every call to deleteSemaphore decreases this counter and if this counter drops to zero, no method 00149 // uses the semaphore any more such that it is safely deleted. Be careful that you don't access the semaphore in a method 00150 // where you already called deleteSemaphore with the semaphore-pointer as parameter. 00151 // 00152 // In order to simplify the handling of ItomSharedSemaphore consider to used ItomSharedSemaphoreLocker. 00153 00154 inline void deleteSemaphore(void) 00155 { 00156 QMutexLocker mutexLocker(&internalMutex); 00157 00158 m_instCounter --; 00159 if(m_instCounter <= 0) 00160 { 00161 m_enableDelete = true; 00162 mutexLocker.unlock(); 00163 delete this; 00164 return; 00165 } 00166 00167 return; 00168 } 00169 00170 ito::RetVal returnValue; 00171 }; 00172 00173 00181 class ItomSharedSemaphoreLocker 00182 { 00183 public: 00185 inline ItomSharedSemaphoreLocker(ItomSharedSemaphore* semaphore) : m_semaphore(semaphore) {} 00186 00188 inline ItomSharedSemaphoreLocker() : m_semaphore(NULL) {} 00189 00191 inline ~ItomSharedSemaphoreLocker() 00192 { 00193 if(m_semaphore) 00194 { 00195 m_semaphore->deleteSemaphore(); 00196 m_semaphore = NULL; 00197 } 00198 } 00199 00201 inline ItomSharedSemaphore* getSemaphore() const { return m_semaphore; } 00202 00204 /* 00205 If this locker already guards an instance of ItomSharedSemaphore its reference counter is decremented first. \sa ItomSharedSemaphore::deleteSemaphore. 00206 */ 00207 inline ItomSharedSemaphoreLocker & operator = (ItomSharedSemaphore *newSemaphoreInstance) 00208 { 00209 if(m_semaphore) 00210 { 00211 m_semaphore->deleteSemaphore(); 00212 m_semaphore = NULL; 00213 } 00214 m_semaphore = newSemaphoreInstance; 00215 return *this; 00216 } 00217 00218 private: 00219 inline ItomSharedSemaphoreLocker(ItomSharedSemaphoreLocker & /*other*/ ) { /* forbidden */ } 00220 inline ItomSharedSemaphoreLocker & operator = (const ItomSharedSemaphoreLocker & /*other*/ ) { return *this; /* forbidden */ } 00221 ItomSharedSemaphore* m_semaphore; 00222 }; 00223 00224 #endif