thread safe vst

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

mystran wrote:
AdmiralQuality wrote:
mystran wrote:
The only concession I make to multithreading in VST plug-ins is to put a critical section around editor::setParameter() and editor::close().
Well, doing that will fix any race conditions. You can still get potential priority inversions, though Windows not being RTOS those will get resolved eventually anyway (though sometimes after some audio drop-outs).
Note that that's editor::setParameter I'm talking about, not effect::setParameter.
Oh ok. Sure. I don't even have such a method anywhere, so I guess this must be something specific to VSTGUI?
Yep, VSTGUI 3.x Sorry for not being more clear.

I'm going to make a test plug-in to see if I can get effect::setParameter called during effect::process. If I'm wrong about this I don't want to be spreading disinformation. (Of course, an editor is free to call effect::setParameter, though it should usually be calling effect::setParameterAutomated Not sure offhand if that doesn't just immediately fire setParameter as well, probably does.

Post

AdmiralQuality wrote:
I'm going to make a test plug-in to see if I can get effect::setParameter called during effect::process. If I'm wrong about this I don't want to be spreading disinformation. (Of course, an editor is free to call effect::setParameter, though it should usually be calling effect::setParameterAutomated Not sure offhand if that doesn't just immediately fire setParameter as well, probably does.
Unless you changed setParameterAutomated, it calls setParameter internally.

Post

mystran wrote:
AdmiralQuality wrote:
I'm going to make a test plug-in to see if I can get effect::setParameter called during effect::process. If I'm wrong about this I don't want to be spreading disinformation. (Of course, an editor is free to call effect::setParameter, though it should usually be calling effect::setParameterAutomated Not sure offhand if that doesn't just immediately fire setParameter as well, probably does.
Unless you changed setParameterAutomated, it calls setParameter internally.
Kinda figured. OK, let me hold off on that claim until I've had a chance to test this empirically.

Post

AdmiralQuality wrote: I'm going to make a test plug-in to see if I can get effect::setParameter called during effect::process.
I'm sure I've had it happen. It can depend on the source of setParameter. So test both manual knob twiddling AND recorded automation playback.
If you think about the timing of effect::process - a plugin using 5% CPU is actually doing nothing 95% of the time, also when it is in process() it's running a higher priority thread than the source of setParameter (the GUI)...so it's less likely to be interrupted part way through process(). However a low priority thread will interrupt a high priority one once it's time quantum expires. These two factors make it less likely that a parameter is set part-way though processing BUT it WILL happen sometimes.
Last edited by Jeff McClintock on Mon Jul 04, 2011 9:12 pm, edited 1 time in total.

Post

Jeff McClintock wrote:
AdmiralQuality wrote: I'm going to make a test plug-in to see if I can get effect::setParameter called during effect::process.
I'm sure I've had it happen. It can depend on the source of setParameter. So test both manual knob twiddling AND recorded automation playback.
If you think about the timing of effect::process - a plugin using 5% CPU is actually doing nothing 95% of the time, also when it is in process() it's running a higher priority thread than the source of setParameter (the GUI)...so it's less likely to be interrupted part way through process().
These two factors make it less likely that a parameter is set part-way though processing BUT it WILL happen sometimes.
I've just put a test for it into DEBUG builds of the products I'm working on. Will keep an eye out for it.

Post

mystran wrote:It depends on the compiler, but assuming MSVC, then unless you specify something other than the defaults (for variables or with compiler switches) you can generally expect any primitive data types of 8-bytes or less (including floats and doubles) to be naturally aligned
OK so if I specify a volatile float then I can expect single load/stores to be atomic.

It's just everything I read makes me paranoid because statements are always qualified with terms like generally. I wouldn't want my code to be generally thread safe. I assume that I am just being paranoid and that this is safe practice?

Post

matt42 wrote:
mystran wrote:It depends on the compiler, but assuming MSVC, then unless you specify something other than the defaults (for variables or with compiler switches) you can generally expect any primitive data types of 8-bytes or less (including floats and doubles) to be naturally aligned
OK so if I specify a volatile float then I can expect single load/stores to be atomic.
Yeah, as long as you don't modify default alignment rules with switches/#pragmas/etc. That pretty much what the "generally" is for: you might be able to convince the compiler to do something else if you try hard enough. ;)

Post

Cool, thanks mystran :)

Post

did you guys see this article about the issue:

http://www.rossbencina.com/code/real-ti ... or-nothing

interesting read

Post

I used spinlocks once as a synchronization primitive for short data sharing (1 GUI thread, 1 audio thead).

Is this a valid approach or would that lead to starving/priority inversions?

Post

ponce wrote:I used spinlocks once as a synchronization primitive for short data sharing (1 GUI thread, 1 audio thead).

Is this a valid approach or would that lead to starving/priority inversions?
You didn't specify enough information: what does the high-priority (audio) thread do when the lock isn't available?

If it goes into some kernel queue waiting (eg OS synchronization primitives) then you have a priority inversion (except on systems which specifically implement "priority inheritance" but I don't think any desktop system does).

If it busy-loops on a classic spinlock, then you have a dead-lock (assuming RT priorities; desktop schedulers usually give up at some point; you'll still starve the GUI thread for a while).

If it notes that it couldn't get the lock right now, and goes on doing other things, trying again some later time (eg while processing the next block) then it's perfectly safe (this is the method I use for moving data from audio to GUI thread; hardly critical if GUI misses some updates, as long as it always gets the latest data so it stays approximately in sync).

Post

The thing is, it's essentially impossible to give very general advice on thread-safety, because you usually have to analyze every possible situation for the specific code in question before you can say whether it's thread-safe or not.

This is why you really want to limit your inter-thread communication to a few general mechanisms that you can "formally" prove correct.

Post

mystran wrote:This is why you really want to limit your inter-thread communication to a few general mechanisms that you can "formally" prove correct.
Best Advice Ever. Don't scatter locks or whatever throughout your code. Make a centralized mechanism like e.g. a 'message pipe' that all your code shares. Your first try WILL BE BUGGY, but at least you only have to fix it in one place.

Post

@mystran: thanks for answering.
You didn't specify enough information: what does the high-priority (audio) thread do when the lock isn't available?
Looping until CAS operation succeed and lock is acquired.

If it busy-loops on a classic spinlock, then you have a dead-lock (assuming RT priorities; desktop schedulers usually give up at some point; you'll still starve the GUI thread for a while).
I think it was the case. However the locking was very short (most often to set or get a 4-byte variable). While I didn't expericence deadlocks at the time, it does not mean it was correct, let alone efficient. :)
If it notes that it couldn't get the lock right now, and goes on doing other things, trying again some later time (eg while processing the next block) then it's perfectly safe (this is the method I use for moving data from audio to GUI thread; hardly critical if GUI misses some updates, as long as it always gets the latest data so it stays approximately in sync).
I would use spinlocks for the opposite, moving parameters from the GUI thread to the audio thread (not a VST).

Post

ponce wrote:I used spinlocks once as a synchronization primitive for short data sharing (1 GUI thread, 1 audio thead).
According to Apple this won't work with Core Audio because the realtime thread is a special kind of thread:
http://lists.apple.com/archives/Coreaud ... 00059.html

Although it may be one of those things that just seems to work until you push it in the wrong way. That's what makes coding with threads so tricky.

Post Reply

Return to “DSP and Plugin Development”