.TH "FBB::SharedCondition" "3bobcat" "2005\-2020" "libbobcat\-dev_5\&.07\&.00" "Shared Memory Cond\&. Var\&." .PP .SH "NAME" FBB::SharedCondition \- Shared Memory Condition Variable .PP .SH "SYNOPSIS" \fB#include \fP .br Linking option: \fI\-lpthread, \-lbobcat \fP .PP .SH "DESCRIPTION" .PP 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\(cq\&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\&. .PP \fBSharedCondition\fP objects can be used in combination with shared memory\&. \fBSharedCondition\fP objects interface to objects (called \fICondition\fP objects in this man\-page) which are defined in shared memory and contain a \fISharedMutex\fP and a shared condition object\&. These \fICondition\fP objects may be accessed by threads running in different processes\&. These different processes might run a single \fImain\fP thread, or they themselves can be multi\-threaded\&. .PP Condition variables are used in situations like these: .IP o There exists a thread which should be suspended until a certain condition has been met\&. .IP o This thread locks a mutex (or waits until the lock has been obtained) .IP o While the condition hasn\(cq\&t been met, the thread is suspended (i\&.e\&., waits), automatically releasing the mutex\(cq\&s lock\&. .IP o Somehow (see below) the thread is resumed, at which point the thread has automatically reacquired the lock\&. .IP o Once the condition has been met, the while loop ends, and the mutex\(cq\&s lock is released\&. .IP o 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\&. .IP o This second thread locks the same mutex as used by the first thread\&. .IP o The second thread modifies the variables that are involved, and if the required condition has been met, it notifies the first thread\&. .IP o The second thread releases the mutex\(cq\&s lock, allowing the first thread to obtain the mutex\(cq\&s lock\&. .PP 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\&. .PP As condition variables are always used in combination with a mutex, \fBSharedMutex\fP encapsulates the mutex\-handling\&. The software using \fBSharedCondition\fP objects doesn\(cq\&t have to handle the mutex itself\&. .PP \fBSharedCondition\fP 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 \fBSharedCondition\fP object is defined in shared memory\&. \fBSharedCondition\fP objects themselves are small objects, containing the necessary information to access the actual shared memory condition variable\&. .PP .SH "NAMESPACE" \fBFBB\fP .br All constructors, members, operators and manipulators, mentioned in this man\-page, are defined in the namespace \fBFBB\fP\&. .PP .SH "INHERITS FROM" \fBSharedMutex\fP(3bobcat) .PP .SH "CONSTRUCTORS, DESTRUCTOR" .IP o \fBSharedCondition()\fP: .br The default constructor creates an empty stub which cannot yet be used (or an \fIFBB::Exception\fP is thrown)\&. As the \fBSharedCondition\fP class supports assignment operators, empty stubs can easily be (re)configured at any time after their construction\&. .IP .IP o \fB~SharedCondition()\fP: .br The class\(cq\&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\&. .PP Default, copy, and move constructors as well as the copy and move assignment operators are available\&. .PP .SH "MEMBER FUNCTIONS" .PP Returning from \fBSharedCondition\fP member functions the offset of the \fISharedMemory\fP 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, \fBSharedCondition\fP member functions can be used disregarding the \fISharedMemory\fP\(cq\&s current offset\&. .PP .IP o \fBvoid lock() const\fP: .br When returning from this member, the current process has locked the \fBSharedCondition\fP object\&. Be careful not to call \fIlock\fP twice during the same thread of execution (cf\&. \fBsharedmutex\fP(3bobcat) for details)\&. .IP .IP o \fBvoid notify() noexept\fP: .br One of the threads waiting on the \fBSharedCondition\fP object wakes up\&. The thread calling \fInotify\fP should release its mutex lock shortly after calling \fInotify\fP, allowing the notified thread to obtain the lock\&. A prototypical piece of pseudo code illustrating the use of \fInotify\fP looks like this: .nf sharedCondition\&.lock(); // lock the mutex \&.\&.\&. // operate on the condition\(cq\&s variables if (conditionWasMet) // ready to notify sharedCondition\&.notify(); sharedCondition\&.unlock(); // release the lock .fi As the \fIsharedCondition\&.lock \&.\&.\&. sharedCondition\&.unlock\fP sequence itself may be executed at different flow of control sections, the \fIunlock\fP member cannot be called from within \fInotify\fP\&. .IP .IP o \fBvoid notifyAll() noexept\fP: .br Different from the plain \fInotify\fP member, this member wakes up all of the threads waiting on the \fBSharedCondition\fP 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 \fInotifyAll\fP is identical to the pseudo code for using \fInotify\fP (i\&.e\&., calling \fInotifyAll\fP, of course)\&. .IP .IP o \fBstd::streamsize offset() const\fP: .br The location of the shared condition variable (within the \fISharedMemory\fP object) is returned\&. The shared condition object ends at \fIoffset() + SharedCondition::width()\fP, see below\&. .IP .IP o \fBvoid unlock() const\fP: .br The object\(cq\&s lock is released (nothing happens if called when the current object does not have the object\(cq\&s lock)\&. .IP .IP o \fBvoid wait()\fP: .br Before calling \fIwait\fP the current thread should have obtained a lock on the \fBSharedCondition\fP object\&. .IP When calling \fIwait\fP 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 \fBSharedCondition\fP object\&. lock\&. A prototypical piece of pseudo code illustrating how to use \fIwait\fP looks like this: .nf sharedCondition\&.lock(); // lock the mutex while (conditionWasNotYetMet) // waiting required sharedCondition\&.wait(); \&.\&.\&. // do something: we have the lock sharedCondition\&.unlock(); // release the lock .fi .IP .IP o \fBvoid wait(Predicate pred)\fP: .br This member was implemented as a member template\&. \fIPredicate\fP either is a predicate function or a predicate function object\&. The predicate function or the predicate function object\(cq\&s function call operators may not require arguments\&. As long as \fIpred\fP is returning false, \fIwait()\fP (no arguments) is called\&. The function returns once \fIpred\fP has returned \fItrue\fP\&. .IP The running thread should have obtained a lock on the \fBSharedCondition\fP condition variable prior to calling this member, and should release the lock after this member has returned\&. .IP The pseudo code for using \fIwait(pred)\fP is identical to the pseudo code for using \fIwait\fP (albeit that \fIpred\fP has to be passed to \fIwait\fP, of course)\&. .IP .IP o \fBstd::cv_status wait_for(std::chrono::duration const &relTime)\fP: .br This member was implemented as a member template\&. \fIType\fP defines the type of the variable holding the amount of time (usually \fIint64_t\fP), specified in time unit \fIUnit\fP\&. Predefined \fIduration\fP types are available from the \fIstd::chrono\fP namespace, like \fIstd::chrono::seconds(4)\fP, representing 4 seconds, or \fIstd::chrono::milliseconds(30)\fP, representing 30 milliseconds\&. .IP The running thread should have obtained a lock on \fBSharedCondition\fP prior to calling this member, and should release the lock after this member has returned\&. .IP This member acts like \fIwait\fP, returning \fIstd::cv_status::no_timeout\fP if a notification was received before \fIrelTime\fP has passed\&. Otherwise \fIstd::cv_status::timeout\fP is returned\&. .IP A prototypical piece of pseudo code illustrating how to use \fIwait_for\fP looks like this: .nf 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 .fi When returning from \fIwait_for\fP the current thread has obtained the shared condition\(cq\&s lock, but maybe due to a timeout: this can be verified by inspecting \fIwait_for\(cq\&s\fP return value, and an appropriate action can be selected\&. .IP .IP o \fBbool wait_for(std::chrono::duration const &relTime, Predicate pred)\fP: .br This member was implemented as a member template\&. \fIType\fP defines the type of the variable holding the amount of time (usually \fIint64_t\fP), specified in time unit \fIUnit\fP\&. \fIPredicate\fP either is a predicate function or a predicate function object\&. The predicate function or the predicate function object\(cq\&s function call operators may not require arguments\&. .IP The running thread should have obtained a lock on \fBSharedCondition\fP prior to calling this member, and should release the lock after this member has returned\&. .IP As long as \fIpred\fP returns false, \fIwait_for(relTime)\fP is called\&. If the latter function returns \fIstd::cv_status::timeout\fP, then \fIpred\fP is called, and its return value is returned\&. Otherwise \fItrue\fP is returned\&. .IP The pseudo code for using this member is identical to the pseudo code for using the abovementioned \fIwait_for\fP member (albeit that \fIpred\fP must also be passed to \fIwait_for\fP, of course)\&. .IP .IP o \fBstd::cv_status wait_until(std::chrono::time_point const &absTime)\fP: .br This member has been implemented as a member template\&. \fIClock\fP defines the clock\-type to use (usually \fIstd::chrono::system_clock\fP), \fIDuration\fP is the type name of a duration type (as used with \fIwait_for\fP)\&. E\&.g\&., to specify 5 seconds after the current time this member could be called like this: .nf std::chrono::system_clock::now() + std::chrono::seconds(5) .fi .IP The running thread should have obtained a lock on \fBSharedCondition\fP prior to calling this member, and should release the lock after this member has returned\&. .IP This member acts like \fIwait_for(relative\-time)\fP, returning \fIstd::cv_status::no_timeout\fP if a notification was received before \fIabsTime\fP has passed\&. Otherwise \fIstd::cv_status::timeout\fP is returned\&. .IP The pseudo code for using this member is identical to the pseudo code for using the abovementioned \fIwait_for(relative\-time)\fP member (albeit that absolute time must be specified)\&. .IP .IP o \fBbool wait_until(std::chrono::time_point const &absTime, Predicate pred)\fP: .br This member was implemented as a member template\&. \fIClock\fP and \fIDuration\fP define identical types as mentioned at the previous member\&. \fIPredicate\fP either is a predicate function or a predicate function object (not expecting arguments)\&. .IP The running thread should have obtained a lock on \fBSharedCondition\fP prior to calling this member, and should release the lock after this member has returned\&. .IP As long as \fIpred\fP returns false, \fIwait_until(absTime)\fP is called\&. If the latter function returns \fIstd::cv_status::timeout\fP, then \fIpred\fP is called, and its return value is returned\&. Otherwise \fItrue\fP is returned\&. .IP The pseudo code for using this member is identical to the pseudo code for using the abovementioned \fIwait_until\fP member (albeit that \fIpred\fP must also be passed to \fIwait_until\fP, of course)\&. .PP .SH "STATIC MEMBER FUNCTIONS" .PP .IP o \fBSharedCondition &attach(SharedMemory &shmem, std::ios::off_type offset = 0, std::ios::seekdir origin = std::ios::beg)\fP: .br The \fISharedCondition\fP object interfacing to the shared condition variable located at \fIoffset\fP (relative to \fIorigin\fP) in \fIshmem\fP is returned\&. .IP An \fIFBB::Exception\fP is thrown if the requested offset is invalid (i\&.e\&., smaller than 0 or exceeding \fIshmem\&.maxOffset()\fP)\&. .IP .IP o \fBFBB::SharedCondition create(SharedMemory &shmem)\fP: .br A shared condition variable is initialized at the current offset of the \fISharedMemory\fP object referred to by \fIshmem\fP, or at the first offset of the next physical shared data segment\&. .IP A \fBSharedCondition\fP object interfacing to the initialized shared condition variable is returned\&. .IP An \fIFBB::Exception\fP is thrown if there isn\(cq\&t enough memory available in the \fISharedMemory\fP object to define a shared condition variable\&. .IP .IP o \fBsize_t size() const\fP: .br Returns the size in bytes of the shared condition variables stored in \fISharedMemory\fP objects\&. .PP .SH "EXAMPLE" .PP .nf #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc == 1) { cout << \(dq\&Argument:\en\(dq\& \(dq\& c: create a shared memory segment + SharedCondition \(dq\& \(dq\&, display ID\en\(dq\& \(dq\& k : kill shared memory segment \en\(dq\& \(dq\& m : show a message every 5 secs, otherwise wait until\en\(dq\& \(dq\& being notified in segment \en\(dq\& \(dq\& n : notify the SharedCondition in segment ID \en\(dq\& ; return 0; } switch (argv[1][0]) { case \(cq\&c\(cq\&: { SharedMemory shmem(1, SharedMemory::kB); SharedCondition cond = SharedCondition::create(shmem); void *ptr = shmem\&.ptr(); cout << \(dq\&ID = \(dq\& << shmem\&.id() << \(dq\&, SharedCondition at \(dq\& << cond\&.offset() << endl; break; } case \(cq\&k\(cq\&: { SharedMemory shmem(stoll(argv[2])); shmem\&.kill(); break; } case \(cq\&m\(cq\&: { SharedMemory shmem(stoll(argv[2])); SharedCondition cond = SharedCondition::attach(shmem); cond\&.lock(); cout << \(dq\&Obtained the lock\&. Now waiting for a notification\en\(dq\&; while (true) { switch (cond\&.wait_for(chrono::seconds(5))) { case cv_status::timeout: cout << \(dq\&Waited for 5 seconds\en\en\(dq\&; break; case cv_status::no_timeout: cond\&.unlock(); cout << \(dq\&Received the notification\&. Unlocked\&.\en\(dq\&; return 0; } } } case \(cq\&w\(cq\&: { SharedMemory shmem(stoll(argv[2])); SharedCondition cond = SharedCondition::attach(shmem); cond\&.lock(); cout << \(dq\&Obtained the lock\&. Now waiting for a notification\en\(dq\&; cond\&.wait(); cout << \(dq\&Received the notification\&. Unlocking\&.\en\(dq\&; cond\&.unlock(); break; } case \(cq\&n\(cq\&: { SharedMemory shmem(stoll(argv[2])); SharedCondition cond = SharedCondition::attach(shmem); cout << \(dq\&Notifying the other after Enter \(dq\&; cin\&.ignore(1000, \(cq\&\en\(cq\&); cond\&.lock(); cout << \(dq\&Obtained the lock\&. Now notifying the other\en\(dq\&; cond\&.notify(); cout << \(dq\&Sent the notification\&. Now unlocking\&.\en\(dq\&; cond\&.unlock(); break; } } } catch (exception const &exc) { cout << \(dq\&Exception: \(dq\& << exc\&.what() << endl; } .fi .PP .SH "FILES" \fIbobcat/sharedcondition\fP \- defines the class interface .PP .SH "SEE ALSO" \fBbobcat\fP(7) \fBisharedstream\fP(3bobcat), \fBosharedstream\fP(3bobcat), \fBsharedblock\fP(3bobcat), \fBsharedmemory\fP(3bobcat), \fBsharedpos\fP(3bobcat), \fBsharedreadme\fP(7bobcat), \fBsharedsegment\fP(3bobcat), \fBsharedstream\fP(3bobcat), \fBsharedbuf\fP(3bobcat) .PP .SH "BUGS" None Reported\&. .PP .SH "BOBCAT PROJECT FILES" .PP .IP o \fIhttps://fbb\-git\&.gitlab\&.io/bobcat/\fP: gitlab project page; .IP o \fIbobcat_5\&.07\&.00\-x\&.dsc\fP: detached signature; .IP o \fIbobcat_5\&.07\&.00\-x\&.tar\&.gz\fP: source archive; .IP o \fIbobcat_5\&.07\&.00\-x_i386\&.changes\fP: change log; .IP o \fIlibbobcat1_5\&.07\&.00\-x_*\&.deb\fP: debian package containing the libraries; .IP o \fIlibbobcat1\-dev_5\&.07\&.00\-x_*\&.deb\fP: debian package containing the libraries, headers and manual pages; .PP .SH "BOBCAT" Bobcat is an acronym of `Brokken\(cq\&s Own Base Classes And Templates\(cq\&\&. .PP .SH "COPYRIGHT" This is free software, distributed under the terms of the GNU General Public License (GPL)\&. .PP .SH "AUTHOR" Frank B\&. Brokken (\fBf\&.b\&.brokken@rug\&.nl\fP)\&. .PP