Race condition when using startThread()


#1

I’ve just been schooled by a crash report:

Calling startThread from a constructor of a class with, where the thread calls a virtual function in the class appears to be a race condition… resulting in my case in a call to the barely documented __cxa_deleted_virtual.

Presumably this is obvious if you know what you are doing? But might worth mentioning in the Thread documentation as there are lots of places in the JUCE code where startThread is executed from the constructor…


#2

https://isocpp.org/wiki/faq/strange-inheritance#calling-virtuals-from-ctors


#3

I’m going to write a little example of the crash I think … I see why it’s happening but I don’t really understand how i got into that mess…


#4

I think you’ll only have a problem if you call startThread in your base class but are actually instantiating a subclass of it.


#5

This appears to be the problem - only with a level of two of indirection to make it harder to spot…


#6

Funny thing is I can’t seem to replicate the exact problem, I get the better error of " Pure virtual function called!" instead of the __cxa_deleted_virtual.

Here’s the problem made obvious:

class Bomb;

class Bomber : public Thread
{
public:
    Bomber(Bomb * bomb) : Thread("detonating thread"), bomb(bomb)
    {
        startThread(5);
        Thread::sleep(500); // some other work that happens...
    }
    void run() override;

    Bomb * bomb;
};

class Bomb
{
public:
    Bomb()
    {

    }
    virtual ~Bomb() {}
    virtual void func() = 0;

    Bomber bomber{this};
};

void Bomber::run()
{
    bomb->func();
}

class ConcreteBomb : public Bomb
{
public:
    ConcreteBomb()
    {
        std::cout << "done" << std::endl;
    }

    void func() override
    {
        std::cout << "worked" << std::endl;
    }

};

int main (int argc, char* argv[])
{
    ConcreteBomb bomb;
    return 0;
}