manager std:string on audio thread: safe?

DSP, Plugin and Host development discussion.
Post Reply New Topic
RELATED
PRODUCTS

Post

Hi there,

I'm going to make a sequencer which will convert some specific patterns (defined as std: string) in notes (midi/cv/trigger signal, basically).

Question is: working with std:string (such as split, add/sub, convert to int) is safe for audio thread? Or does it could involve heap/memory allocation at runtime (= glitch)?

Note: it will processed/generated only when pattern start/restart (so once every x samples), but not sure this has some meaning (heap allocation for a single sample is bad in any case).

Thanks for any hints.

Post

Out of the box, std::string will likely allocate/deallocate unless you're very careful (creating them outside the audio thread, only doing safe stuff like reading on the audio thread).

But note that std::string is a specialization of the template std::basic_string, which supports custom allocators. So you could probably use a custom allocator or a std::polymorphic_allocator with enough pre-allocated space for strings on the audio thread.

However, is it really strictly necessary to process those strings on the audio thread? If they're created from some GUI interaction you could process them in the message thread into some symbolic or object representation that tells the DSP code what to do through a message queue or something (e.g. notes, parameter changes). Similarly, if the strings need to be created from audio analysis, you could go the other way around. What you're writing doesn't sound like the strings need to actually live on the audio thread.

Post

Derozer wrote: Fri Mar 29, 2024 5:26 pm I'm going to make a sequencer which will convert some specific patterns (defined as std: string) in notes (midi/cv/trigger signal, basically).
You probably should not. Even if the patterns are input as strings, you should probably parse (and store) them as some easier to handle binary data right where they are input. You should typically do this even if there was no real-time considerations to worry about, because this allows you to isolate all the string handling in one place and rest of your code does not need to worry about whether the strings actually contain valid data.
Question is: working with std:string (such as split, add/sub, convert to int) is safe for audio thread? Or does it could involve heap/memory allocation at runtime (= glitch)?
Whether or not you actually should do it (you should not), you can safely access the contents of the string, but pretty much anything that actually changes the string will cause an allocation and therefore potentially a glitch. If you're working with recent enough C++ standard then I'd imagine you could perhaps split strings by creating the substrings as stringviews, which is basically a range over character data... but honestly you should probably do all this stuff (strings or not) in GUI thread and just pass the final results to the audio thread if possible.
Note: it will processed/generated only when pattern start/restart (so once every x samples), but not sure this has some meaning (heap allocation for a single sample is bad in any case).
Any amount of memory allocation in audio thread is a potential problem... and in fact when you allocate, you typically end up also deallocating previous chunks and that's also potentially risky.

The issue here is that the way memory allocators are designed, they try to be as efficient as possible on average and it's the on average part that's a problem for real-time. Most memory allocations (and deallocations) will be satisfied quickly (unless the allocator really sucks) and will not cause a glitch... but then once in a while it'll happen that the memory allocator doesn't just have the correct size block waiting for you and needs to go and start doing more complicated things... or just randomly decides to do a bit of cleanup or bookkeeping maintenance or whatever... and it's the "once in a while some allocation can be really slow" that is the real problem for a real-time thread, because real-time threads don't care about averages, they care about hitting their deadlines.

In other words, when you allocate, most of the time the allocator grabs a block from a freelist and that's it. Most of the time when you deallocate it puts that block back to the freelist and that's it... but if you build a memory allocator that only ever does this, you'll find that it performs poorly on average, because the heap will get all fragmented.. and that's why memory allocators have to do a bit more and if they decide to do that "bit more" when it's your realtime thread calling, that's a glitch.

Post

Everyone is correct.

I want to add that on some 64 bit platforms you might get away with strings under 23 bytes not allocating at all because of short string optimization.

https://stackoverflow.com/questions/216 ... on-in-libc

Totally platform and stdlib implementation dependent. Probably not testable at compile time. Rely on it at your own risk.

Post

Just to maintain the discussion, with C++20, you can get some insight into the short string optimization by declaring a constexpr std::string global variable and looking at which point the compiler stops allowing it. Visual Studio is particularly funny about it; right now it allows me up to 15 characters, but only in non-debug mode (not /MDd).

Post Reply

Return to “DSP and Plugin Development”