.. _Condvars:

.. raw:: html

   <script>ODSA.SETTINGS.DISP_MOD_COMP = true;ODSA.SETTINGS.MODULE_NAME = "Condvars";ODSA.SETTINGS.MODULE_LONG_NAME = "Condition Variables";ODSA.SETTINGS.MODULE_CHAPTER = "Synchronization Primitives"; ODSA.SETTINGS.BUILD_DATE = "2021-06-01 12:51:47"; ODSA.SETTINGS.BUILD_CMAP = false;JSAV_OPTIONS['lang']='en';JSAV_EXERCISE_OPTIONS['code']='java';</script>


.. |--| unicode:: U+2013   .. en dash
.. |---| unicode:: U+2014  .. em dash, trimming surrounding whitespace
   :trim:


.. This file is part of the OpenCSF eTextbook project. It was
.. auto-generated by scripts from the OpenDSA eTextbook project.
.. See https://OpenCSF.org for more details. OpenCSF is distributed
.. under a Creative Commons Attribution-NonCommercial 4.0 International
.. License (see http://creativecommons.org/licenses/by-nc/4.0/),
.. Copyright (c) 2019-2021 by Michael S. Kirkpatrick. OpenDSA is
.. distributed under an MIT open source license, Copyright (c) 2012-2021
.. by the OpenDSA Project Contributors.

.. avmetadata::
   :author: Michael S. Kirkpatrick
   :requires:
   :satisfies: 
   :topic: 

Condition Variables
===================

One of the primary uses of semaphores is to perform application-specific
signaling. One thread waits on a semaphore until another thread indicates that
some important event has occurred. While semaphores are flexible, they have a
number of short-comings for many programs.

   * Semaphore operations do not adhere to strong principles of encapsulation and
     abstraction. That is, the practice of incrementing and decrementing an integer
     value does not have an obvious mapping to synchronization problems. For
     instance, this contrasts with the more intuitive *lock* and *unlock* operations
     on mutex locks.
   * There are several different implementations of semaphores that vary in the
     features that they provide. Furthermore, different systems provide varying
     levels of support and compliance in their semaphore implementations.
   * In most implementations, semaphores can only send a signal to one other thread
     (or process) at a time. Semaphores provide no mechanism for broadcasting
     messages to multiple other threads.
   * When receiving a signal, threads have to perform an extra step to secure
     mutually exclusive access to shared data. The delay in the timing between the
     signal and acquiring the mutex can introduce race conditions.

:term:`Condition variables <condition variable>` overcome many of these
short-comings of semaphores. Similar to the POSIX semaphore interface, condition
variables provide *wait* and *signal* functions. These provide a more natural
mapping to the problems of synchronization, as one or more threads are waiting
on a signal from another thread that a condition has occurred.

.. topic:: C library functions – <pthread.h>

   .. figure:: Images/CSF-Images-Library.png
      :align: left
      :width: 100%
      :alt: Decorative C library image

   ``int pthread_cond_init (pthread_cond_t *cond, const pthread_condattr_t *attr);``
     Initialize a condition variable.

   ``int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex);``
     Release a mutex, wait on a condition, then re-acquire the mutex.

   ``int pthread_cond_signal (pthread_cond_t *cond);``
     Send a signal to a waiting thread.

   ``int pthread_cond_broadcast (pthread_cond_t *cond);``
     Send a signal to all waiting threads.

   ``int pthread_cond_destroy (pthread_cond_t *cond);``
     Delete a condition variable and clean up its associated resources.


Condition Variables vs. Semaphores
----------------------------------

Condition variables and semaphores appear very similar, as they both provide a
mechanism that allow threads to signal that a custom event has occurred. But the
differences between condition variables and semaphore signaling go beyond just a
shift in terminology.

   * The ``pthread_cond_wait()`` function performs multiple functions. It first
     releases the mutex and blocks until the corresponding signal is received; it
     then re-acquires the mutex that had been locked. Specifically, both of these
     actions are considered to occur atomically; unless an error occurs, the thread
     is guaranteed to have acquired the mutex by the time the function returns.
   * Condition variables support broadcasting. The ``pthread_cond_broadcast()``
     function will notify all threads that are waiting on the condition. Moreover,
     each thread will resume one at a time with the mutex acquired. With the
     additional mutual exclusion guarantees, condition variables can be combined in
     a thread-safe manner with other pieces of data to make the condition more meaningful.
   * Condition variables are a standard part of the POSIX thread library, and they
     are more widely supported. For instance, some systems include the unnamed POSIX
     semaphore interface, but the implementation is empty, as named semaphores are
     preferred. There is no similar distinction in condition variables, and there is
     wider support for them.

How to Use a Condition Variable
-------------------------------

There are several conventional practices for condition variables that may not be immediately obvious.

   * A thread must acquire the mutex before calling ``pthread_cond_wait()``, which
     will release the mutex. Calling ``pthread_cond_wait()`` without having locked
     the mutex leads to undefined behavior.
   * Calls to ``pthread_cond_wait()`` should be made inside a while loop. The POSIX
     specification allows threads to wake up even if the signal was not sent (called
     a *spurious wake up*). By checking the return value of ``pthread_cond_wait()``,
     the thread can determine if the wake up was spurious and go back to waiting if necessary.
   * Just calling ``pthread_cond_signal()`` or ``pthread_cond_broadcast()`` is
     insufficient to wake up waiting threads, as the threads are locked by the mutex
     rather than the condition variable. The functions must be followed by a call to
     ``pthread_mutex_unlock()``, which will allow ``pthread_cond_wait()`` to acquire
     the mutex and return.

A Condition Variable Example
----------------------------

The following sample program uses one thread read lines of keyboard input from
``STDIN``, then passing on the information to two other threads. If the input is
a string, the second thread gets the length of the string and adds it to a
counter. If the input can be converted to an long using ``strtol()``, then the
integer value is added to the counter by the third thread.

The threads all rely on the following shared ``struct``. The ``input_cond``
condition variable is used to indicate that a line of input has been received.
The ``input_processed_cond`` variable is used to indicate that the two helper
threads have processed the input and the keyboard listener can get more input.
The other fields are used to pass information between the threads.

.. codeinclude:: Synch/CondVarStruct.c
   :linenos: true

The keyboard listener starts by acquiring the mutex, guaranteeing that this
thread has mutually exclusive access to the shared data. After reading a line of
input with ``fgets()``, this thread tries to convert the input to an long with
``strtol()``. If so, it sets the current_value field to this integer value. If
not, the string is checked against the string ``"shutdown"``, which is used to
make the program stop. In all three cases, ``pthread_cond_broadcast()`` signals
to the other threads that input has been received. The listener then waits on
the ``input_processed_cond`` condition, which indicates that the input has been
processed completely by another thread. Finally, if the shutdown message was
received, this thread sets a boolean value that the others detect during another
broadcast. `Code Listing 7.15 <#cl7-15>`_ shows the keyboard listener thread.

.. _cl7-15:

.. codeinclude:: Synch/CodeListing-7-15.c
   :linenos: true

`Code Listing 7.16 <#cl7-16>`_ shows the additional threads that share this
data. The ``count_chars()`` and ``add_number()`` threads behave in approximately
the same manner. They both start by acquiring the mutex, then waiting on the
``input_cond``. In both cases, the call to ``pthread_cond_wait()`` releases the
lock at this point. Once the signal has been received and the mutex is
re-acquired, the threads check if they need to shutdown. If not, they each check
if the input was a string. Only the ``count_chars()`` thread processes string
input, whereas only the ``add_number()`` thread processes numeric input. If the
thread is not supposed to process input, it uses continue to go back to the
beginning of the loop and wait on the condition again. If the thread did process
its appropriate input, it signals on the ``input_processed_cond`` variable,
which allows ``keyboard_listener()`` to move on to reading the next line of input.

.. _cl7-16:

.. codeinclude:: Synch/CodeListing-7-16.c
   :linenos: true

.. topic:: Bug Warning

   .. figure:: Images/CSF-Images-BugWarning.png
      :align: left
      :width: 90%
      :alt: Decorative bug warning

   For completeness, both the ``count_chars()`` and ``add_number()`` threads should
   check the return value of ``pthread_cond_wait()`` to determine if the signal
   was spurious. However, this code omits this check for brevity and algorithmic clarity.

Finally, `Code Listing 7.17 <#cl7-17>`_ illustrates how to initialize the
condition variables, create the threads, and clean up all of the resources for
the condition variables and the mutex.

.. _cl7-17:

.. codeinclude:: Synch/CodeListing-7-17.c
   :linenos: true

Monitors and Synchronized Methods
---------------------------------

.. _SynchMonitor:

.. figure:: Images/CSF-Images.7.2.png
   :align: right
   :width: 90%
   :figwidth: 45%
   :alt: Architecture of a monitor with synchronized data access

   Architecture of a monitor with synchronized data access

The preceding code is an example of an object-oriented construct known as a
monitor. :num:`Figure #SynchMonitor` illustrates the general
architecture of a :term:`monitor`. Specifically, a monitor is a class or data
structure that combines condition variables, mutexes, and other
application-specific data. All of the internal data is considered private to the
monitor, and other pieces of code can only interact with the monitor by invoking
a method on the object.

The key characteristic of a monitor is that all methods are mutually exclusive
in execution. That is, as with the thread functions above, methods in a monitor
begin by locking the monitor's mutex. Doing so guarantees that only one thread
is *in the monitor* at any given moment. The method ends by releasing the mutex,
allowing other threads to enter the monitor.

Within the monitor, there are associated condition variables to synchronize
access between the monitor and the general execution environment. While the
methods are executing, they can use these condition variables to detect key
events or to check for safe conditions. If the condition variable check (i.e.,
``pthread_cond_wait()``) fails, then the thread must release the mutex and exit
the monitor. The thread then waits in the condition variable's associated
waiting queue until it can resume execution.

Readers familiar with the Java synchronized keyword have been essentially using
monitors by a different name. That is, the primary function of the synchronized
keyword is to have injected code that acquires a hidden mutex at the beginning
of the method execution, then releases it when returning.


.. avembed:: Exercises/Synch/SynchCondvarSumm.html ka
   :module: Condvars
   :points: 1.0
   :required: True
   :exer_opts: JXOP-debug=true&amp;JOP-lang=en&amp;JXOP-code=java
   :long_name: Condition variable questions
   :threshold: 5

