Lights, buttons and thread-safety

Recently I’ve started my journey into Rack development. I’ve read several topics about the best practices for the communication between modules and widgets, in particular for what concerns thread safety and the ways the usual audio development patterns (no locking, no allocations, etc.) are implemented in Rack.

I’ve started reading how, for example, light brightness is updated from the module.process() method. The usual way is to use Light.setBrightness(), which simply updates its value property. This value is read by a widget inside its step() method to perform its drawing operations.

If I’m not wrong module.process() is run inside the audio thread, while widget.step() is run from the main thread, and neither Light.setBrightness() nor Light.getBrightness() implement a (lock-free) synchronization mechanism. I wonder how thread-safety is granted for this and other similar cases.

I think access to params, lights and such is through some wrapper function on the Widget side, isn’t it? But in any case those things tend to be 32-bit values that are already atomic on the CPUs that rack runs on, aren’t they?

I any case, there have never been reports of issues around that, so I wouldn’t worry.

I’m not worried, and I believe there are good reasons for doing it that way.

Mine was more a question to understand the underlying mechanisms, and if the same approach (assignment and reading of primitivs types) could be safely used even outside the process() and step() methods.

BTW I thought that r/w synchroziation was also required for primitive types (std::atomic). Wasn’t it?

yes, but rather than assuming that underlying stuff is atomic you could use std::atomic and be explicit about it. like I did here: SquinkyVCV-main/composites/Compressor2.h at master · kockie69/SquinkyVCV-main · GitHub

Or for my explicitly multi threaded non-blocking modules: SquinkyVCV-main/sqsrc/thread/ThreadSharedState.h at master · kockie69/SquinkyVCV-main · GitHub

Thx @Squinky. My questions arose while I was reading parts of your code*. I see you’ve been more explicit on this when compared to some of the Core modules.

Is it correct to say that if I’m not much concerned with the reader seeing the updated value immediately (which could be fine for widgets), the atomic nature of primitive values could be enough without bringing up std::atomic?

*I’m extending your Seq++ to support MIDI Velocity. It’s almost complete (parse from midi file, drawing end editind notes velocities, etc.)

ah, nice! Yeah, I guess when I used all the atomic stuff (years ago!) I wanted to be “correct” rather than rely on assumptions about CPU. I had been programming a bit on the old PPC mac, where did not have a “coherent memory architecture”. But relying on stuff to just work is absolutely fine, of course.