Message queues in SObjectizer dispatchers use synchronization objects to protect the contents of the queue when working with it from several threads. Synchronization objects are created with the help of special factories (so-called lock_factory). The developer can point which particular lock_factory should be used when creating specific dispatcher.
This feature is available since 5.5.10 and 5.5.11 versions. Also since then two types of lock_factories were implemented:
combined_lock_factory
creates combined synchronization objects. Such object consists of two parts – spin-lock and simple mutex. The capture of such object is performed in a tricky way: first there are several attempts to capture spin-lock with call to std::this_thread::yield
between unsuccessful attempts. If spin-lock is not captured then there is an attempt to capture mutex. Doing this during prolonged waiting the thread, which tries to capture the synchronization object, provides operation system an opportunity to fall asleep until the resource is available. Such combined synchronization objects show good results in heavy loads when there is an intensive message exchange and no one waits long to get some work;simple_lock_factory
creates synchronization objects based on simple mutex. That is the thread, which attempts to capture the resource obtained by someone, will simply fall asleep waiting for mutex to be released. When the mutex is released the operation system will wake the sleeping thread and push it to execution. Such synchronization objects are more expensive but the application consumes almost no resources in case message chains are empty (nobody is using cores for nothing on spin-locks).By default combined_lock_factory
is used. This can be changed in message queue properties to simple_lock_factory
if needed.
Before version 5.5.18 it was possible to replace combined_lock_factory
with simple_lock_factory
only for one separate dispatcher. That is when creating dispatcher in its queue_traits simple_lock_factory
is selected. Which was uncomfortable if the application created more than one dispatcher (or even more than ten): one had to remember to configure the queue_traits for each of them.
Even worse if the application uses ready-made library of agents inside of which its own dispatcher instances are created. Likely this library doesn’t provide an opportunity to configure queue_traits for its own dispatchers but uses the default parameters of queue_traits, i.e. combined_lock_factory
will be used.
In version 5.5.18 this defect was fixed by adding the feature to set the default lock_factories for the whole SObjectizer Environment. That is if all application’s dispatchers in their queues should use only simple_lock_factory
by default this can be configured via environment_params_t
since version 5.5.18. For example:
so_5::launch( []( so_5::environment_t & env ) { ... // Some initial actions. }, []( so_5::environment_params_t & params ) { // Use simple_lock_factory for event queues by default. params.queue_locks_defaults_manager( so_5::make_defaults_manager_for_simple_locks() ); ... } );
After that for dispatcher creation the following scenario is used:
simple_lock_factory
. Herewith the application doesn’t care where particular the dispatcher is created: in the application code or in the third-party library. If the lock_factory is not set explicitly when creating dispatcher then the lock_factory will be used by default.
If the developer didn’t set queue_locks_defaults_manager explicitly during SObjectizer Environment start then combined_lock_factory
will be used by default. So the default behavior of dispatchers and queues in SObjectizer in version 5.5.18 is not changed.