/* * utilite is a cross-platform library with * useful utilities for fast and small developing. * Copyright (C) 2010 Mathieu Labbe * * utilite is free library: 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 3 of the License, or * (at your option) any later version. * * utilite 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 this program. If not, see . */ /* * Originally written by Phillip Sitbon * Copyright 2003 */ #ifndef USEMAPHORE_H #define USEMAPHORE_H #include #ifdef _WIN32 #include "rtabmap/utilite/Win32/UWin32.h" #define SEM_VALUE_MAX ((int) ((~0u) >> 1)) #else #include #include #endif /** * A semaphore class. * * On an acquire() call, the calling thread is blocked if the * USemaphore's value is <= 0. It is unblocked when release() is called. * The function acquire() decreases by 1 (default) the * semaphore's value and release() increases it by 1 (default). * * Example: * @code * USemaphore s; * s.acquire(); // Will wait until s.release() is called by another thread. * @endcode * * @see UMutex */ class USemaphore { public: /** * The constructor. The semaphore waits on acquire() when its value is <= 0. * @param n number to initialize */ USemaphore( int initValue = 0 ) { #ifdef _WIN32 S = CreateSemaphore(0,initValue,SEM_VALUE_MAX,0); #else _available = initValue; pthread_mutex_init(&_waitMutex, NULL); pthread_cond_init(&_cond, NULL); #endif } virtual ~USemaphore() { #ifdef _WIN32 CloseHandle(S); #else pthread_cond_destroy(&_cond); pthread_mutex_destroy(&_waitMutex); #endif } /** * Acquire the semaphore. If semaphore's value is <=0, the * calling thread will wait until the count acquired is released. * @see release() * @param n number to acquire * @param t time to wait (ms), a value <=0 means infinite * @return true on success, false on error/timeout */ #ifdef _WIN32 bool acquire(int n = 1, int ms = 0) const { int rt = 0; while(n-- > 0 && rt==0) { rt = WaitForSingleObject((HANDLE)S, ms<=0?INFINITE:ms); } return rt == 0; } #else bool acquire(int n = 1, int ms = 0) { int rt = 0; pthread_mutex_lock(&_waitMutex); while (n > _available && rt == 0) { if(ms > 0) { struct timespec timeToWait; struct timeval now; gettimeofday(&now,NULL); timeToWait.tv_sec = now.tv_sec + ms/1000; timeToWait.tv_nsec = (now.tv_usec+1000UL*(ms%1000))*1000UL; rt = pthread_cond_timedwait(&_cond, &_waitMutex, &timeToWait); } else { rt = pthread_cond_wait(&_cond, &_waitMutex); } } if(rt == 0) { // only remove them if waiting did not fail _available -= n; } pthread_mutex_unlock(&_waitMutex); return rt == 0; } #endif /* * Try to acquire the semaphore, not a blocking call. * @return false if the semaphore can't be taken without waiting (value <= 0), true otherwise */ #ifdef _WIN32 int acquireTry() const { return ((WaitForSingleObject((HANDLE)S,INFINITE)==WAIT_OBJECT_0)?0:EAGAIN); } #else int acquireTry(int n) { pthread_mutex_lock(&_waitMutex); if(n > _available) { pthread_mutex_unlock(&_waitMutex); return false; } _available -= n; pthread_mutex_unlock(&_waitMutex); return true; } #endif /** * Release the semaphore, increasing its value by 1 and * signaling waiting threads (which called acquire()). */ #ifdef _WIN32 int release(int n = 1) const { return (ReleaseSemaphore((HANDLE)S,n,0)?0:ERANGE); } #else void release(int n = 1) { pthread_mutex_lock(&_waitMutex); _available += n; pthread_cond_broadcast(&_cond); pthread_mutex_unlock(&_waitMutex); } #endif /** * Get the USempahore's value. * @return the semaphore's value */ #ifdef _WIN32 int value() const { LONG V = -1; ReleaseSemaphore((HANDLE)S,0,&V); return V; } #else int value() { int value = 0; pthread_mutex_lock(&_waitMutex); value = _available; pthread_mutex_unlock(&_waitMutex); return value; } #endif #ifdef _WIN32 /* * Reset the semaphore count. * @param init the initial value * TODO implement on posix ? */ void reset( int init = 0 ) { CloseHandle(S); S = CreateSemaphore(0,init,SEM_VALUE_MAX,0); } #endif private: void operator=(const USemaphore &S){} #ifdef _WIN32 USemaphore(const USemaphore &S){} HANDLE S; #else USemaphore(const USemaphore &S):_available(0){} pthread_mutex_t _waitMutex; pthread_cond_t _cond; int _available; #endif }; #endif // USEMAPHORE_H