Thread-safe game engine: multi-threading best practices?
I'm wondering about best practices around waiting for threads.


That's too big a question. Instead I'll just review your existing code.


  This is my current implementation, and I'm realizing it's not ideal.


You construct this with a bool async parameter, so that it loads synchronously or asynchronously. There are (at least) two alternatives.

One is to make two derived subclasses:

class Texture
{
    ... etc ...
    virtual ~Texture() {}
protected:
    Texture(const char *filename)
    {
        this-&gt;filename = filename;
    }
    static int load(void *data);
private:
    virtual void wait() = 0;
    const char *filename;
}

class SyncTexture : public Texture {
public:
    SyncTexture(const char *filename)
    : Texture(filename)
    {
        load(this);
    }
private:
    virtual void wait() {} // do nothing
};

class AsyncTexture : public Texture {
public:
    AsyncTexture(const char *filename)
    : Texture(filename)
    {
        thread = SDL_CreateThread(load, NULL, this);
    }
private:
    SDL_Thread *thread;
    virtual void wait() { SDL_WaitThread(thread, NULL); }
};


The above is similar to what you might have been suggesting when you talked about a "function pointer": i.e. wait is 'virtual' and called through a so-called vtable.

The second possibility is to do it using templates:

template &lt;bool async = true&gt;
class Texture {
public:
    Texture(const char *filename);
};


This may be faster at run-time, because the value of async is known/fixed at compile-time.


  Convert the "wait()" method in to a function pointer.


I don't understand what you're thinking of when you say this, and you haven't provided the source code for it.


  I've also considered just using the "inline" keyword on the function... but would this include the entire contents of the wait function when all I really need is the "if (thread != NULL)" check to determine whether the rest of the code should be executed or not?


I guess that wait is small and simple enough to be inlined.

The "rest of the code" is only the following ...

{
    SDL_WaitThread(thread, NULL);
    thread = NULL;
}


... and it wouldn't be called if thread is null: so what are you worrying about: the increase in size of your software? I doubt you have enough methods (places where you call wait), such that inlining them would make significant difference to the size of your code.