The Open Master Hearing Aid (openMHA)  openMHA
Open community platform for hearing aid algorithm research
MHAPlugin::config_t< runtime_cfg_t > Class Template Reference

Template class for thread safe configuration. More...

Inheritance diagram for MHAPlugin::config_t< runtime_cfg_t >:
Inheritance graph

Public Member Functions

 config_t ()
 
 ~config_t ()
 

Protected Member Functions

runtime_cfg_t * poll_config ()
 Receive the latest run time configuration. More...
 
runtime_cfg_t * peek_config () const
 Receive the latest run time configuration without changing the configuration pointer. More...
 
void push_config (runtime_cfg_t *ncfg)
 Push a new run time configuration into the configuration fifo. More...
 
void cleanup_unused_cfg ()
 To be called by the push_config() for housekeeping. More...
 
void remove_all_cfg ()
 To be called on Plugin destruction, will delete all runtime configuration list nodes and objects regardless of their in_use flag. More...
 

Protected Attributes

runtime_cfg_t * cfg
 Pointer to the runtime configuration currently used by the signal processing thread. More...
 

Private Attributes

std::atomic< MHAPlugin::cfg_node_t< runtime_cfg_t > * > cfg_root
 Start of a singly linked list of runtime configuration objects. More...
 
MHAPlugin::cfg_node_t< runtime_cfg_t > * cfg_node_current
 Pointer to the currently used plugin runtime configurations. More...
 

Detailed Description

template<class runtime_cfg_t>
class MHAPlugin::config_t< runtime_cfg_t >

Template class for thread safe configuration.

This template class provides a mechanism for the handling of thread safe configuration which is required for run time configuration changes of the openMHA plugins.

The template parameter runtime_cfg_t is the run time configuration class of the openMHA plugin. The constructor of that class should transform the MHAParser variables into derived runtime configuration. The constructor should fail if the configuration is invalid by any reason.

A new runtime configuration is provided by the function push_config(). In the processing thread, the actual configuration can be received by a call of poll_config().

config_fifo_2.png
Schematic drawing of runtime configuration update: configuration updated, but not used yet.
config_fifo_3.png
Schematic drawing of runtime configuration update: configuration in use.

To ensure lock-free thread safety, we use C++11 atomics and rely on the C++11 memory model. We only use store-release and load-acquire operations by using C++11 atomics with the default memory ordering. The semantics of these are:

The store-release operation atomically writes to an atomic variable, while the load-acquire operation atomically reads from an atomic variable.

The C++11 memory model guarantees that all previous writes to memory performed by the thread doing the store-release are visible to other threads when they see the new value in the shared atomic variable when that value is read by the other thread with a load-acquire operation.

An important precondition of this synchronization scheme is that there is only ever one audio thread and one configuration thread per plugin, i.e. there is only one thread doing the push_config and one thread doing the poll_config for each instance of config_t.

For more details on atomics, refer to the C++11 or later documentation, or to these conference talks by Sutter:

  • Atomic Weapons, 2012
  • Lock-Free Programming, 2014

Constructor & Destructor Documentation

◆ config_t()

template<class runtime_cfg_t >
MHAPlugin::config_t< runtime_cfg_t >::config_t ( )

◆ ~config_t()

template<class runtime_cfg_t >
MHAPlugin::config_t< runtime_cfg_t >::~config_t ( )

Member Function Documentation

◆ poll_config()

template<class runtime_cfg_t >
runtime_cfg_t * MHAPlugin::config_t< runtime_cfg_t >::poll_config ( )
protected

Receive the latest run time configuration.

This function stores the latest run time configuration into the protected class member variable `cfg'. If no configuration exists, then an exception will be thrown. If no changes occured, then the value of `cfg' will be untouched.

This function should be only called from the processing thread.

Should be called at the start of each process() callback to get the latest runtime configuration.

When this function finds newer run time configurations, it returns the newest and ensures the older run time configurations have their not_in_use flag set to true.

Returns
Pointer to the latest runtime configuration object (same pointer as stored by this function in data member `cfg').
Exceptions
MHA_Errorif the resulting runtime configuration is NULL. This usually means that no push_config has occured.

◆ peek_config()

template<class runtime_cfg_t >
runtime_cfg_t * MHAPlugin::config_t< runtime_cfg_t >::peek_config ( ) const
protected

Receive the latest run time configuration without changing the configuration pointer.

This function retrieves the latest run time configuration. Returns a pointer to the latest runtime configuration without updating the data member cfg. For use in the configuration thread when creation of a new runtime configuration object needs access to the previously created runtime configuration object. Should normally not be used because it introduces synchronization requirements between configuration thread and signal processing thread.

◆ push_config()

template<class runtime_cfg_t>
void MHAPlugin::config_t< runtime_cfg_t >::push_config ( runtime_cfg_t *  ncfg)
protected

Push a new run time configuration into the configuration fifo.

Should be called only by the configuration thread when a new runtime configuration object has been constructed in response to configuration changes, or during execution of the prepare() method to ensure that there is a valid runtime configuration for the signal processing which can start after prepare() returns.

For housekeeping, this method will also delete any runtime configuration objects that have previously been passed to push_config() if they are no longer needed.

Parameters
ncfgA pointer to the new runtime configuration object. This object must have been created on the heap by the configuration thread with operator new. By passing the pointer to this method, client code gives up ownership. The object will be deleted in a future invocation of push_config, or on destruction of this config_t instance.

◆ cleanup_unused_cfg()

template<class runtime_cfg_t >
void MHAPlugin::config_t< runtime_cfg_t >::cleanup_unused_cfg ( )
protected

To be called by the push_config() for housekeeping.

Will delete any no longer used runtime configuration objects.

◆ remove_all_cfg()

template<class runtime_cfg_t >
void MHAPlugin::config_t< runtime_cfg_t >::remove_all_cfg ( )
protected

To be called on Plugin destruction, will delete all runtime configuration list nodes and objects regardless of their in_use flag.

Member Data Documentation

◆ cfg

template<class runtime_cfg_t>
runtime_cfg_t* MHAPlugin::config_t< runtime_cfg_t >::cfg
protected

Pointer to the runtime configuration currently used by the signal processing thread.

Should be used to access the current runtime configuration during signal processing. This pointer is updated as a side effect of calling poll_config() on this object.

◆ cfg_root

template<class runtime_cfg_t>
std::atomic< MHAPlugin::cfg_node_t<runtime_cfg_t> *> MHAPlugin::config_t< runtime_cfg_t >::cfg_root
private

Start of a singly linked list of runtime configuration objects.

cfg_root points to the oldest still existing node of that list. After object creation this pointer is updated by the configuration thread and then read by the signal processing thread. To ensure proper order of memory accesses for this transfer between threads, it needs to be atomic, this ensures that the start of the singly linked list of runtime configurations will be properly visible to the signal processing on startup.

◆ cfg_node_current

template<class runtime_cfg_t>
MHAPlugin::cfg_node_t<runtime_cfg_t>* MHAPlugin::config_t< runtime_cfg_t >::cfg_node_current
private

Pointer to the currently used plugin runtime configurations.

Used as a hint for poll_config where to start looking for the newest node. This optimization allows poll_config to scale better with the number of nodes not yet cleaned up by push_config. Does not need to be atomic because it is only used within the signal processing thread.


The documentation for this class was generated from the following file: