---
name: "sharedcondition"
section: "3bobcat"
platform: "linux"
package: "libbobcat-dev"
version: "6.07.01-2"
release: "Debian 13 (Trixie)"
platforms: ["linux"]
url: "https://new.carta.tech/sharedcondition"
---

# sharedcondition(3bobcat)

Shared Memory Condition Variable

## NAME

FBB::SharedCondition - Shared Memory Condition Variable

## SYNOPSIS

**#include \<bobcat/sharedcondition\>**\
 Linking option: *-lpthread, -lbobcat*

## DESCRIPTION

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.

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

Condition variables are used in situations like these:

- o

  There exists a thread which should be suspended until a certain condition has been met.

- o

  This thread locks a mutex (or waits until the lock has been obtained)

- o

  While the condition hasn’t been met, the thread is suspended (i.e., waits), automatically releasing the mutex’s lock.

- o

  Somehow (see below) the thread is resumed, at which point the thread has automatically reacquired the lock.

- o

  Once the condition has been met, the while loop ends, and the mutex’s lock is released.

- 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.

- o

  This second thread locks the same mutex as used by the first thread.

- o

  The second thread modifies the variables that are involved, and if the required condition has been met, it notifies the first thread.

- o

  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, **SharedMutex** encapsulates the mutex-handling. The software using **SharedCondition** objects doesn’t have to handle the mutex itself.

**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 **SharedCondition** object is defined in shared memory.  **SharedCondition** objects themselves are small objects, containing the necessary information to access the actual shared memory condition variable.

## NAMESPACE

**FBB**\
 All constructors, members, operators and manipulators, mentioned in this man-page, are defined in the namespace **FBB**.

## INHERITS FROM

**SharedMutex**(3bobcat)

## CONSTRUCTORS, DESTRUCTOR

- o

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

-

  - o

  **~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 as well as the copy and move assignment operators are available.

## MEMBER FUNCTIONS

Returning from **SharedCondition** member functions the offset of the *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, **SharedCondition** member functions can be used disregarding the *SharedMemory*’s current offset.

- o

  **void lock() const**:\
   When returning from this member, the current process has locked the **SharedCondition** object. Be careful not to call *lock* twice during the same thread of execution (cf. [**sharedmutex**(3bobcat)](/sharedmutex/3bobcat.md) for details).

-

  - o

  **void notify() noexept**:\
   One of the threads waiting on the **SharedCondition** object wakes up. The thread calling *notify* should release its mutex lock shortly after calling *notify*, allowing the notified thread to obtain the lock. A prototypical piece of pseudo code illustrating the use of *notify* looks like this:

  ```
      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 *sharedCondition.lock ... sharedCondition.unlock* sequence itself may be executed at different flow of control sections, the *unlock* member cannot be called from within *notify*.

-

  - o

  **void notifyAll() noexept**:\
   Different from the plain *notify* member, this member wakes up all of the threads waiting on the **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 *notifyAll* is identical to the pseudo code for using *notify* (i.e., calling *notifyAll*, of course).

-

  - o

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

-

  - o

  **void unlock() const**:\
   The object’s lock is released (nothing happens if called when the current object does not have the object’s  lock).

-

  - o

  **void wait()**:\
   Before calling *wait* the current thread should have obtained a lock on the **SharedCondition** object.

-

  When calling *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 **SharedCondition** object.  lock. A prototypical piece of pseudo code illustrating how to use *wait* looks like this:

  ```
      sharedCondition.lock();         // lock the mutex
      while (conditionWasNotYetMet)   // waiting required
          sharedCondition.wait();
      ...                             // do something: we have the lock
      sharedCondition.unlock();       // release the lock
  ```

-

  - o

  **void wait(Predicate pred)**:\
   This member was implemented as a member template. *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 *pred* is returning false, *wait()* (no arguments) is called. The function returns once *pred* has returned *true*.

-

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

-

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

-

  - o

  **std::cv\_status wait\_for(std::chrono::duration\<Type, Unit\>** **const &relTime)**:\
   This member was implemented as a member template. *Type* defines the type of the variable holding the amount of time (usually *int64\_t*), specified in time unit *Unit*. Predefined *duration* types are available from the *std::chrono* namespace, like *std::chrono::seconds(4)*, representing 4 seconds, or *std::chrono::milliseconds(30)*, representing 30 milliseconds.

-

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

-

  This member acts like *wait*, returning *std::cv\_status::no\_timeout* if a notification was received before *relTime* has passed. Otherwise *std::cv\_status::timeout* is returned.

-

  A prototypical piece of pseudo code illustrating how to use *wait\_for* looks like this:

  ```
      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 *wait\_for* the current thread has obtained the shared condition’s lock, but maybe due to a timeout: this can be verified by inspecting *wait\_for’s* return value, and an appropriate action can be selected.

-

  - o

  **bool wait\_for(std::chrono::duration\<Type, Unit\>** **const &relTime, Predicate pred)**:\
   This member was implemented as a member template. *Type* defines the type of the variable holding the amount of time (usually *int64\_t*), specified in time unit *Unit*. *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 **SharedCondition** prior to calling this member, and should release the lock after this member has returned.

-

  As long as *pred* returns false, *wait\_for(relTime)* is called. If the latter function returns *std::cv\_status::timeout*, then *pred* is called, and its return value is returned. Otherwise *true* is returned.

-

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

-

  - o

  **std::cv\_status wait\_until(std::chrono::time\_point\<Clock, Duration\>** **const &absTime)**:\
   This member has been implemented as a member template. *Clock* defines the clock-type to use (usually *std::chrono::system\_clock*), *Duration* is the type name of a duration type (as used with *wait\_for*). E.g., to specify 5 seconds after the current time this member could be called like this:

  ```
      std::chrono::system_clock::now() + std::chrono::seconds(5)
  ```

-

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

-

  This member acts like *wait\_for(relative-time)*, returning *std::cv\_status::no\_timeout* if a notification was received before *absTime* has passed. Otherwise *std::cv\_status::timeout* is returned.

-

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

-

  - o

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

-

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

-

  As long as *pred* returns false, *wait\_until(absTime)* is called. If the latter function returns *std::cv\_status::timeout*, then *pred* is called, and its return value is returned. Otherwise *true* is returned.

-

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

## STATIC MEMBER FUNCTIONS

- o

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

-

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

-

  - o

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

-

  A **SharedCondition** object interfacing to the initialized shared condition variable is returned.

-

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

-

  - o

  **size\_t size() const**:\
   Returns the size in bytes of the shared condition variables stored in *SharedMemory* objects.

## EXAMPLE

```
#include <iostream>
#include <bobcat/sharedcondition>
#include <bobcat/sharedmemory>
using namespace std;
using namespace FBB;
int main(int argc, char **argv)
try
{
    if (argc == 1)
    {
        cout <<
            "Argument:\n"
            "   c: create a shared memory segment + SharedCondition "
                                                    ", display ID\n"
            "   k <id>: kill shared memory segment <id>\n"
            "   m <id>: show a message every 5 secs, otherwise wait until\n"
            "           being notified in segment <id>\n"
            "   n <id>: notify the SharedCondition in segment ID <id>\n"
        ;
        return 0;
    }
    switch (argv[1][0])
    {
        case ’c’:
        {
            SharedMemory shmem(1, SharedMemory::kB);
            SharedCondition cond = SharedCondition::create(shmem);
            void *ptr = shmem.ptr();
            cout << "ID = " << shmem.id() << ", SharedCondition at " <<
                    cond.offset() << endl;
            break;
        }
        case ’k’:
        {
            SharedMemory shmem(stoll(argv[2]));
            shmem.kill();
            break;
        }
        case ’m’:
        {
            SharedMemory shmem(stoll(argv[2]));
            SharedCondition cond = SharedCondition::attach(shmem);
            cond.lock();
            cout << "Obtained the lock. Now waiting for a notification\n";
            while (true)
            {
                switch (cond.wait_for(chrono::seconds(5)))
                {
                    case cv_status::timeout:
                        cout << "Waited for 5 seconds\n\n";
                    break;
                    case cv_status::no_timeout:
                        cond.unlock();
                        cout << "Received the notification. Unlocked.\n";
                    return 0;
                }
            }
        }
        case ’w’:
        {
            SharedMemory shmem(stoll(argv[2]));
            SharedCondition cond = SharedCondition::attach(shmem);
            cond.lock();
            cout << "Obtained the lock. Now waiting for a notification\n";
            cond.wait();
            cout << "Received the notification. Unlocking.\n";
            cond.unlock();
            break;
        }
        case ’n’:
        {
            SharedMemory shmem(stoll(argv[2]));
            SharedCondition cond = SharedCondition::attach(shmem);
            cout << "Notifying the other after Enter ";
            cin.ignore(1000, ’\n’);
            cond.lock();
            cout << "Obtained the lock. Now notifying the other\n";
            cond.notify();
            cout << "Sent the notification. Now unlocking.\n";
            cond.unlock();
            break;
        }
    }
}
catch (exception const &exc)
{
    cout << "Exception: " << exc.what() << endl;
}
```

## FILES

*bobcat/sharedcondition* - defines the class interface

## SEE ALSO

[**bobcat**(7)](/bobcat/7.md) [**isharedstream**(3bobcat)](/isharedstream/3bobcat.md), [**osharedstream**(3bobcat)](/osharedstream/3bobcat.md), [**sharedblock**(3bobcat)](/sharedblock/3bobcat.md), [**sharedmemory**(3bobcat)](/sharedmemory/3bobcat.md), [**sharedpos**(3bobcat)](/sharedpos/3bobcat.md), [**sharedreadme**(7bobcat)](/sharedreadme/7bobcat.md), [**sharedsegment**(3bobcat)](/sharedsegment/3bobcat.md), [**sharedstream**(3bobcat)](/sharedstream/3bobcat.md), [**sharedbuf**(3bobcat)](/sharedbuf/3bobcat.md)

## BUGS

None Reported.

## BOBCAT PROJECT FILES

- o

  *https://fbb-git.gitlab.io/bobcat/*: gitlab project page;

Debian Bobcat project files:

- o

  *libbobcat6*: debian package containing the shared library, changelog and copyright note;

- o

  *libbobcat-dev*: debian package containing the static library, headers, manual pages, and developer info;

## BOBCAT

Bobcat is an acronym of \`Brokken’s Own Base Classes And Templates’.

## COPYRIGHT

This is free software, distributed under the terms of the GNU General Public License (GPL).

## AUTHOR

Frank B. Brokken (**f.b.brokken@rug.nl**).
