includefile(include/header)

COMMENT(manpage, section, releasedate, archive, short name)
manpage(FBB::SharedCondition)(3bobcat)(_CurYrs_)
        (libbobcat-dev__CurVers_-x.tar.gz)(Shared Memory Cond. Var.)

manpagename(FBB::SharedCondition)(Shared Memory Condition Variable)

manpagesynopsis()
    bf(#include <bobcat/sharedcondition>)nl()
    Linking option: tt(-lpthread, -lbobcat ) 

manpagedescription()

    Condition variables are used to synchronize threads based on the values of
data. Condition variables allow threads to wait until a certain condition has
occurred, after which the threads continue their actions. Thus waiting threads
don't continuously have to poll the state of a variable (requiring the threads
to gain access to the variable before they can inspect its value). Using
condition variables waiting threads simply wait until they are notified.

    bf(SharedCondition) objects can be used in combination with shared
memory. bf(SharedCondition) objects interface to objects (called em(Condition)
objects in this man-page) which are defined in shared memory and contain a
tt(SharedMutex) and a shared condition object. These tt(Condition) objects may
be accessed by threads running in different processes. These different
processes might run a single tt(main) thread, or they themselves can be
multi-threaded.

    Condition variables are used in situations like these:
    itemization(
    it() There exists a thread which should be suspended until a certain
        condition has been met. 
    it() This thread locks a mutex (or waits until the lock has been obtained)
    it() While the condition hasn't been met, the thread is suspended (i.e.,
        waits), automatically releasing the mutex's lock. 
    it() Somehow (see below) the thread is resumed, at which point the thread
        has automatically reacquired the lock.
    it() Once the condition has been met, the while loop ends, and the mutex's
        lock is released.
    it() There exists a second thread, which influences the variables that are
        elements of the condition, and which may notify the waiting thread,
        once the required condition has been met.
    it() This second thread locks the same mutex as used by the first thread.
    it() The second thread modifies the variables that are involved, and if
        the required condition has been met, it notifies the first thread.
    it() The second thread releases the mutex's lock, allowing the first
        thread to obtain the mutex's lock. 
    )

While the first thread is waiting, it is suspended. It may be resumed when it
receives a notification from another thread, but also for spurious
reasons. Therefore the first thread must verify that the condition has been
met after resuming its actions.

As condition variables are always used in combination with a mutex,
bf(SharedMutex) encapsulates the mutex-handling. The software using
bf(SharedCondition) objects doesn't have to handle the mutex itself.

bf(SharedCondition) objects are used to synchronize actions by different
processes, using shared memory as their vehicle of
synchronization/communication. The actual condition variable that is used by a
bf(SharedCondition) object is defined in shared memory.  bf(SharedCondition)
objects themselves are small objects, containing the necessary information to
access the actual shared memory condition variable.

includefile(include/namespace)

manpagesection(INHERITS FROM)
    bf(SharedMutex)(3bobcat)

manpagesection(CONSTRUCTORS, DESTRUCTOR)
    itemization(
    itb(SharedCondition())
       The default constructor creates an empty stub which cannot yet be used
        (or an tt(FBB::Exception) is thrown). As the bf(SharedCondition) class
        supports assignment operators, empty stubs can easily be
        (re)configured at any time after their construction.

    itb(~SharedCondition())
       The class's destructor releases (if applicable) its lock on the shared
        condition variables mutex lock. The destructor takes no action if its
        object is an empty stub.
    )
       (Default) copy and move constructors are available. 

manpagesection(OVERLOADED OPERATORS)

    The (default) overloaded move and copy assignment operators are available.

manpagesection(MEMBER FUNCTIONS)

Returning from bf(SharedCondition) member functions the offset of the
tt(SharedMemory) object in which the condition variable has been defined has
not changed. Internally, the current offset is saved; the requested function
is performed; and the original offset is restored. Consequently,
bf(SharedCondition) member functions can be used disregarding the
tt(SharedMemory)'s current offset.

    itemization(
    itb(void lock() const)
       When returning from this member, the current process has locked the
        bf(SharedCondition) object. Be careful not to call tt(lock) twice
        during the same thread of execution (cf. bf(sharedmutex)(3bobcat) for
        details).

    itb(void notify() noexept)
       One of the threads waiting on the bf(SharedCondition) object wakes
        up. The thread calling tt(notify) should release its mutex lock
        shortly after calling tt(notify), allowing the notified thread to
        obtain the lock. A prototypical piece of pseudo code illustrating
        the use of tt(notify) looks like this:
       verb(
    sharedCondition.lock();     // lock the mutex
    ...                         // operate on the condition's variables
    if (conditionWasMet)        // ready to notify
        sharedCondition.notify(); 
    sharedCondition.unlock();   // release the lock
       )
       As the tt(sharedCondition.lock ... sharedCondition.unlock) sequence
        itself may be executed at different flow of control sections, the
        tt(unlock) member cannot be called from within tt(notify).

    itb(void notifyAll() noexept)
       Different from the plain tt(notify) member, this member wakes up all of
        the threads waiting on the bf(SharedCondition) object. However, after
        the current thread has released its mutex lock only one of these
        signaled threads will actually obtain the lock. The pseudo code for
        using tt(notifyAll) is identical to the pseudo code for using
        tt(notify) (i.e., calling tt(notifyAll), of course).

    itb(std::streamsize offset() const)
       The location of the shared condition variable (within the
        tt(SharedMemory) object) is returned. The shared condition object ends
        at tt(offset() + SharedCondition::width()), see below.

    itb(void unlock() const)
       The object's lock is released (nothing happens if called when the
        current object does not have the object's  lock).

    itb(void wait())
       Before calling tt(wait) the current thread should have obtained a lock
        on the bf(SharedCondition) object. 

       When calling tt(wait) the running thread suspends its activities and
        waits until being notified. Once notified, it reacquires the lock and
        continues. Shortly after this the process should again release its
        lock on the bf(SharedCondition) object.  lock. A prototypical piece of
        pseudo code illustrating how to use tt(wait) looks like this:
       verb(
    sharedCondition.lock();         // lock the mutex
    while (conditionWasNotYetMet)   // waiting required
        sharedCondition.wait(); 
    ...                             // do something: we have the lock
    sharedCondition.unlock();       // release the lock
       )

    itb(void wait(Predicate pred))
       This member was implemented as a member template. tt(Predicate) either
        is a predicate function or a predicate function object. The predicate
        function or the predicate function object's function call operators
        may not require arguments. As long as tt(pred) is returning false,
        tt(wait()) (no arguments) is called. The function returns once
        tt(pred) has returned tt(true).

        The running thread should have obtained a lock on the
        bf(SharedCondition) condition variable prior to calling this member,
        and should release the lock after this member has returned.

        The pseudo code for using tt(wait(pred)) is identical to the pseudo
        code for using tt(wait) (albeit that tt(pred) has to be passed to
        tt(wait), of course).

    itb(std::cv_status wait_for(std::chrono::duration<Type, Unit> 
        const &relTime))
       This member was implemented as a member template. tt(Type) defines the
        type of the variable holding the amount of time (usually tt(int64_t)),
        specified in time unit tt(Unit). Predefined tt(duration) types are
        available from the tt(std::chrono) namespace, like
        tt(std::chrono::seconds(4)), representing 4 seconds, or
        tt(std::chrono::milliseconds(30)), representing 30 milliseconds.

        The running thread should have obtained a lock on bf(SharedCondition)
        prior to calling this member, and should release the lock after this
        member has returned.

        This member acts like tt(wait), returning
        tt(std::cv_status::no_timeout) if a notification was received before
        tt(relTime) has passed. Otherwise tt(std::cv_status::timeout) is
        returned.

        A prototypical piece of pseudo code illustrating how to use
        tt(wait_for) looks like this:
       verb(
    sharedCondition.lock();         // lock the mutex
    while (conditionWasNotYetMet)   // waiting required
    {
        while (sharedCondition.wait_for(someTime) 
               == std::cv_status::timeout)
            handle_timeout 

        do_something
    }
    sharedCondition.unlock();       // release the lock
       )
       When returning from tt(wait_for) the current thread has obtained the
        shared condition's lock, but maybe due to a timeout: this can be
        verified by inspecting tt(wait_for's) return value, and an appropriate
        action can be selected.

    itb(bool wait_for(std::chrono::duration<Type, Unit> 
        const &relTime, Predicate pred))
       This member was implemented as a member template. tt(Type) defines the
        type of the variable holding the amount of time (usually tt(int64_t)),
        specified in time unit tt(Unit). tt(Predicate) either is a predicate
        function or a predicate function object.  The predicate function or
        the predicate function object's function call operators may not
        require arguments. 

        The running thread should have obtained a lock on bf(SharedCondition)
        prior to calling this member, and should release the lock after this
        member has returned.

        As long as tt(pred) returns false, tt(wait_for(relTime)) is called. If
        the latter function returns tt(std::cv_status::timeout), then
        tt(pred) is called, and its return value is returned. Otherwise
        tt(true) is returned.

        The pseudo code for using this member is identical to the pseudo code
        for using the abovementioned tt(wait_for) member (albeit that tt(pred)
        must also be passed to tt(wait_for), of course).

    itb(std::cv_status wait_until(std::chrono::time_point<Clock, Duration> 
        const &absTime))
       This member has been implemented as a member template. tt(Clock)
        defines the clock-type to use (usually tt(std::chrono::system_clock)),
        tt(Duration) is the type name of a duration type (as used with
        tt(wait_for)). E.g., to specify 5 seconds after the current time this
        member could be called like this:
       verb(
    std::chrono::system_clock::now() + std::chrono::seconds(5)
        )

        The running thread should have obtained a lock on bf(SharedCondition)
        prior to calling this member, and should release the lock after this
        member has returned.

        This member acts like tt(wait_for(relative-time)), returning
        tt(std::cv_status::no_timeout) if a notification was received before
        tt(absTime) has passed. Otherwise tt(std::cv_status::timeout) is
        returned.

        The pseudo code for using this member is identical to the pseudo code
        for using the abovementioned tt(wait_for(relative-time)) member
        (albeit that absolute time must be specified).

    itb(bool wait_until(std::chrono::time_point<Clock, Duration> 
        const &absTime, Predicate pred))
       This member was implemented as a member template. tt(Clock) and
        tt(Duration) define identical types as mentioned at the previous
        member.  tt(Predicate) either is a predicate function or a predicate
        function object (not expecting arguments).

        The running thread should have obtained a lock on bf(SharedCondition)
        prior to calling this member, and should release the lock after this
        member has returned.

        As long as tt(pred) returns false, tt(wait_until(absTime))
        is called. If the latter function returns tt(std::cv_status::timeout),
        then tt(pred) is called, and its return value is returned. Otherwise
        tt(true) is returned.

        The pseudo code for using this member is identical to the pseudo code
        for using the abovementioned tt(wait_until) member (albeit that
        tt(pred) must also be passed to tt(wait_until), of course).
    )

manpagesection(STATIC MEMBER FUNCTIONS)

    itemization(
    itb(SharedCondition &attach(SharedMemory &shmem,
                        std::ios::off_type offset = 0,
                        std::ios::seekdir origin = std::ios::beg))
       The tt(SharedCondition) object interfacing to the shared condition
        variable located at tt(offset) (relative to tt(origin)) in tt(shmem)
        is returned. 

        An tt(FBB::Exception) is thrown if the requested offset is invalid
        (i.e., smaller than 0 or exceeding tt(shmem.maxOffset())).

    itb(FBB::SharedCondition create(SharedMemory &shmem)) 
       A shared condition variable is initialized at the current offset of
        the tt(SharedMemory) object referred to by tt(shmem), or at the first
        offset of the next physical shared data segment. 

        A bf(SharedCondition) object interfacing to the initialized shared
        condition variable is returned.

        An tt(FBB::Exception) is thrown if there isn't enough memory available
        in the tt(SharedMemory) object to define a shared condition variable.

    itb(size_t size() const)
       Returns the size in bytes of the shared condition variables stored in
        tt(SharedMemory) objects.
    )

manpagesection(EXAMPLE)
    
    verbinclude(../../sharedcondition/driver/driver.cc)


manpagefiles()
    em(bobcat/sharedcondition) - defines the class interface

manpageseealso()
    bf(bobcat)(7)
        bf(isharedstream)(3bobcat),
        bf(osharedstream)(3bobcat),
        bf(sharedblock)(3bobcat), 
        bf(sharedmemory)(3bobcat),
        bf(sharedpos)(3bobcat), 
        bf(sharedreadme)(7bobcat), 
        bf(sharedsegment)(3bobcat), 
        bf(sharedstream)(3bobcat), 
        bf(sharedstreambuf)(3bobcat)

manpagebugs()
    None Reported.

includefile(include/trailer)
