/* * Copyright (C) 2007-2023 Xagasoft, All rights reserved. * * This file is part of the libbu++ library and is released under the * terms of the license contained in the file LICENSE. */ #ifndef BU_COUNTER_EVENT_H #define BU_COUNTER_EVENT_H #include #include "bu/mutex.h" #include "bu/condition.h" namespace Bu { /** * Represents a true/false state that controls thread synchronization. This * is primarilly intended to control the synchronization state of * multithreaded services. For example, telling all threads when to exit. * * An Event is either set or unset. If the Event is unset then it can be * waited on for something to happen. As soon as the Event is set all * waiting threads are released and new requests to wait are ignored until * the Event is cleared again. * * Threads can also be woken up without setting the Event, which may be * handy in certain circumstances. *@ingroup Threading */ class CounterEvent { public: CounterEvent() : iCount( 0 ) { } ~CounterEvent() { } /** * Wait indefinitely for the Event to trigger. If the event is already * set, then return immediately. It's important to note that this may * return at any time, not only when the Event is set, so examining the * return value is important. *@returns the set status of the Event. */ int wait() { cBlock.lock(); if( iCount == 0 ) { cBlock.unlock(); return iCount; } cBlock.wait(); int iRet = iCount; cBlock.unlock(); return iRet; } /** * Wait for up to nSec seconds and nUSec nanoseconds for the event to * trigger. If the Event is already set then return immediately. *@returns the set status of the Event. */ int wait( int nSec, int nUSec ) { cBlock.lock(); if( iCount == 0 ) { cBlock.unlock(); return iCount; } cBlock.wait( nSec, nUSec ); bool iRet = iCount; cBlock.unlock(); return iRet; } /** * Allow one of the waiting threads to unlock without updating the set * state of the Event. */ void unblockOne() { cBlock.lock(); cBlock.signal(); cBlock.unlock(); } /** * Allow all waiting threads to unlock and proceed without updating the * set state of the Event. */ void unblockAll() { cBlock.lock(); cBlock.broadcast(); cBlock.unlock(); } /** * Find out if the Event is in the set state or not. *@returns True if set, false otherwise. */ bool isZero() { cBlock.lock(); bool bRet = (iCount == 0); cBlock.unlock(); return bRet; } /** * Sets the Event's state to true and triggers all waiting threads. */ void decrement() { cBlock.lock(); iCount--; if( iCount < 0 ) iCount = 0; if( iCount == 0 ) cBlock.broadcast(); cBlock.unlock(); } void increment() { cBlock.lock(); iCount++; cBlock.unlock(); } /** * Sets the Event's state to false. This does NOT trigger any waiting * threads. */ void clear() { cBlock.lock(); iCount = 0; cBlock.unlock(); } private: Condition cBlock; /**< The condition for blocking dequeues. */ int iCount; }; } #endif