Thread-safe messaging design problem.

Hello fellow engineers,

I have a technical design problem (software) for a personal project that has left me scratching my head. Maybe you can help!

This is likely an extremely common design issue and can be easily solved, but I wonder if there are unique approaches that I havent stumbled across yet.

All comments/questions/feedback are welcome and encouraged, thanks in advance for your time.

Here is a basic description of the problem:

I have multiple threads/modules in my firmware system (zephyr) that need to update a set of shared parameters.

When a thread updates a parameter, all other threads that are interested in this parameter should have their local value updated.

This needs to occur synchronously for some parameters, and for others it can be asychronous.

From my current experiments there seems to be multiple ways to approach this.

Some additional criteria:

  • Not all threads care about all parameters, therefore I dont want each thread to have a local copy of the complete parameter structure.
  • There will be a variety of modules/systems/threads running in the system that take advantage of this.
  • Parameter updates could be in the 100/s - 1000/s.

My current approach is to use a central dispatcher with an input message queue (fifo).
All threads post to this queue, and then the dispatcher has a “recipient” table that it uses to lookup and “dispatch” the updated values to the subscribed parties.

Some other questions/ideas floating in my head -
- Could a database be suitable? E.g. SQLite.

Thanks for your time!


1 Like

This is an interesting question and a core question of modern applications – how do you manage state in an application?

Shared state is tricky and generally not recommended, so I think you are on the right track with keeping local copies of the state needed.

I have used the above approach with good success a number of times. In my case, each thread had an input queue. All messages were sent to a central thread that had a case statement that looked at message type and then forwarded the message to whatever threads were interested. Very simple, but effective.

Lately I’ve been moving more toward event bus models (ex: NATS in Go applications). See: Architecture - Simple IoT

For Zephyr, have you looked at zbus yet?

Databases like SQLite are very powerful and fit more into the shared state model. One problem with this is is you don’t have visibility into all the data flowing through the system. With your central dispatcher or an event bus, any data can be observed by anyone else in real-time without polling the database/state. This is very useful.

This is a popular theme in Go programs:

Do not communicate by sharing memory; instead, share memory by communicating.

I think I move forward with the central dispatcher as a prototype, and use a simple interface for message posting that allows me to change the underlying implementation later on. Then I can do some benchmark testing and evaluate if I need to move to a different system.

I do like the approach that Go uses, but I’m constrained to an embedded system (C/C++).