1
0
mirror of https://github.com/stefanocasazza/ULib.git synced 2025-09-28 19:05:55 +08:00
ULib/include/ulib/utility/semaphore.h
stefanocasazza b5184ba45e sync
2018-07-27 18:11:02 +02:00

138 lines
4.3 KiB
C++

// ============================================================================
//
// = LIBRARY
// ULib - c++ library
//
// = FILENAME
// semaphore.h
//
// = AUTHOR
// Stefano Casazza
//
// ============================================================================
#ifndef ULIB_SEMAPHORE_H
#define ULIB_SEMAPHORE_H 1
#include <ulib/internal/common.h>
#ifdef HAVE_SEMAPHORE_H
# include <semaphore.h>
#elif !defined(HAVE_SEM_INIT)
typedef int sem_t;
# ifdef HAVE_OLD_IOSTREAM
extern "C" { int sem_getvalue(sem_t* sem, int* sval); }
# endif
#endif
class ULib;
class ULock;
class UTimeVal;
class Application;
class UServer_Base;
/**
* A data race occurs when two threads access the same variable concurrently and at least one of the accesses is write
*
* A semaphore is generally used as a synchronization object between multiple threads or to protect a limited and finite
* resource such as a memory or thread pool. The semaphore has a counter which only permits access by one or more threads
* when the value of the semaphore is non-zero. Each access reduces the current value of the semaphore by 1. One or more
* threads can wait on a semaphore until it is no longer 0, and hence the semaphore can be used as a simple thread
* synchronization object to enable one thread to pause others until the thread is ready or has provided data for them.
* Semaphores are typically used as a counter for protecting or limiting concurrent access to a given resource, such as
* to permitting at most "x" number of threads to use resource "y", for example
*/
class U_EXPORT USemaphore {
public:
// Check for memory error
U_MEMORY_TEST
// Allocator e Deallocator
U_MEMORY_ALLOCATOR
U_MEMORY_DEALLOCATOR
USemaphore()
{
U_TRACE_CTOR(0, USemaphore, "")
next = U_NULLPTR;
psem = U_NULLPTR;
}
/**
* The initial value of the semaphore can be specified. An initial value is often used when used to lock a finite
* resource or to specify the maximum number of thread instances that can access a specified resource.
*
* @param resource specify initial resource count or 1 default
*/
void init(sem_t* ptr = U_NULLPTR, int resource = 1);
/**
* Destroying a semaphore also removes any system resources associated with it. If a semaphore has threads currently
* waiting on it, those threads will all continue when a semaphore is destroyed
*/
~USemaphore();
/**
* Wait is used to keep a thread held until the semaphore counter is greater than 0. If the current thread is held, then
* another thread must increment the semaphore. Once the thread is accepted, the semaphore is automatically decremented,
* and the thread continues execution.
*
* @return false if timed out
* @param timeout period in milliseconds to wait
*/
bool wait(time_t timeoutMS);
/**
* Posting to a semaphore increments its current value and releases the first thread waiting for the semaphore
* if it is currently at 0. Interestingly, there is no support to increment a semaphore by any value greater than 1
* to release multiple waiting threads in either pthread. Hence, if one wants to release a semaphore to enable multiple
* threads to execute, one must perform multiple post operations
*/
void lock();
void unlock() { post(); }
static USemaphore* first; // active list
#if defined(U_STDCPP_ENABLE) && defined(DEBUG)
const char* dump(bool) const;
#endif
protected:
USemaphore* next;
#if defined(__MACOSX__) || defined(__APPLE__)
sem_t* psem;
char name[24];
#elif defined(_MSWINDOWS_) || (defined(HAVE_SEM_INIT) && (!defined(U_LINUX) || LINUX_VERSION_CODE > KERNEL_VERSION(2,6,7)))
sem_t* psem;
#else
int psem;
#endif
void post();
static bool checkForDeadLock(UTimeVal& time); // NB: check if process has restarted and it had a lock active...
#if !defined(__MACOSX__) && !defined(__APPLE__) && defined(HAVE_SEM_GETVALUE) && (!defined(U_LINUX) || LINUX_VERSION_CODE > KERNEL_VERSION(2,6,7))
int getValue() { int value = -1; (void) sem_getvalue(psem, &value); return value; }
#else
int getValue() { return -1; }
#endif
private:
U_DISALLOW_COPY_AND_ASSIGN(USemaphore)
friend class ULib;
friend class ULock;
friend class Application;
friend class UServer_Base;
};
#endif