Finishing my first plugin - threading/crash issues, is this causing it?

I’ve a couple of questions as I’m coming to finalizing my first plugin.

  1. What could be causing these crashes - is a threading issue likely
  2. What tools can I use in Visual Studio 2020 that can help me track it down?

My plugin seems to be working well, but every day or two, after its been running 10 minutes or more, it will suddenly crash - it just wipes the DAW out, and exits.

The theory is that I am accessing/writing to variables in the processor from the editor, and those variables are being changed simultaneously by two different threads - a race condition. Hence the crash.

I’ve heard of FIFO and am looking into that. But is it possible, in the editor, when I am trying to change a processor variable to do that via a Setter, rather than do it directly?

Example existing code in the Editor: audioProcessor.myFlagVariable = true;
Proposed replacement: audioProcessor.setmyFlagVariable(true);
i.e. calling a method in the processor to manipulate the variable.

Is using locking a good way:

public:
    void setMyFlagVariable(bool value) {
        std::lock_guard<std::mutex> lock(myFlagVariableMutex);
        myFlagVariable = value;
    }

And, I assume that employing a Getter is even recommended for reading a variable from the processor, because even reading can cause a race condition…

My second question is, what tools do you recommend (hopefully within VS2020) that are good at tracking down the cause of crashes like this?

A race condition doesn’t automatically mean a crash, you may simply get wrong results, which is potentially worse than a crash since the code could simply continue running while producing the wrong output.

If that one bool variable in the processor is the only thing you need to manipulate from the GUI, you can just make the bool an atomic std::atomic<bool> myFlagVariable;

That likely doesn’t solve your sporadic crashing issue, though. The issue is likely somewhere else. We’d ideally need to see all of your code to understand better what the issue could be.

1 Like

You should be able to run your host in the debugger on Visual Studio, iirc you right click the target in Visual Studio and choose the preferences option, from there on the left there is a debugger section where you can set the executable to be your host. Then when you choose “debug” from Visual Studio it will launch the host, you open your plugin and hope the crash happens, at which point VS should halt showing you the stack trace and problem code.

One thing I would suggest (pure speculation here) is to open and close then open again your plugin editor and tweak parameters. It’s really easy to forget to unregister a listener which can be the source of crash when some listener is holding a dangling pointer to an already destructed editor. Of course might be something else entirely.

Good luck!

edit: quick bit of Le Goog searching suggests you can launch the host and then use Debug → Attach to process from the main menus. I’m currently in macOS so can’t check for sure, but I remember it was a slight PITA for me when first figuring out how to launch the host in debug mode from VS.

1 Like

I’ve got about twelve variables that I am accessing from the editor.

Has std::atomic<bool> myFlagVariable; got less overhead than a mutex lock?

I’m also accessing methods to find values in the processor to ascertain values to do with my volume meter, this is in timercallback as I’m updating my volume meter regularly. Could something like this cause race conditions too?

    //PluginEditor.cpp in timercallback()
    float analogVolumeMeterL = (audioProcessor.getRMSValue(0));
    float analogVolumeMeterR = (audioProcessor.getRMSValue(1));
float mypluginprocessor::getRMSValue(const int channel) const
{
    if (channel == 0)
        return rmsLevelLeft.getCurrentValue();
    if(channel == 1)
        return rmsLevelRight.getCurrentValue();
    return 0.f;
}
    //rmsLevelLeft.skip(buffer.getNumSamples());
    //rmsLevelRight.skip(buffer.getNumSamples());
    //(both juce::LinearSmoothedValue<float>)

There’s another way to called FIFO, I’ll have to investigate, probably(?)

I doubt it is race conditions causing a crash.

But we have a lot of variables that the editor queries or modifies in the processor class using std::atomic. If it’s something that is used when processing, we generally set a value and set an atomic flag saying the value has changed, and the processor picks those up at the very start of every process call, grabbing the new value and using exchange(false) to reset the flag.

1 Like

To make access to the current level variable thread safe, wrapping it into atomic is enough and the way to go.
For small variables atomic can achieve thread safety without a lock. You can make sure of it with:

std::static_assert(std::atomic<float>::is_always_lock_free());

If that adds a lock, you get an intentional compiler error.
[1] std::atomic<T>::is_always_lock_free - cppreference.com

The mutex is a bad idea. When the GUI and the processBlock contest the same mutex, you get a priority inversion, so the audio thread waits for the slow GUI thread and might create drop outs.

That doesn’t explain a crash, but something to consider.

1 Like

And then in PluginEditor use getters and setters?

//PluginProcessor.h
std::atomic<float> myVariable;
static_assert(std::atomic<float>::is_always_lock_free());

    void setMyVariable(float value) {
        myVariable.store(value);    }

    float getMyVariable() const {
        return myVariable.load();    }

//PluginEditor.cpp
audioProcessor.setMyVariable(12.0f);

@daniel @xenakios @asimilon
After implementing the atomics, and moving some non-trivial types values to trivial atomic ones, my plugin isn’t crashing.
I also read the APVTS is not thread safe, so I might look at a safer way of using that, possibly a flag as @HowardAntares suggests.