2

I'm working on a game engine that runs from a .dll. Inside, there is an exported function that returns a reference to a static class declared in it, like below:

__forceinline __declspec(dllexport) STATE* NF3DGetEngineState(void)
{
    static STATE s_State;
    return &s_State;
}

where STATE is a class that manages all components and has functions that accesses them via a critical section:

void Set(int val)
{
    EnterCriticalSection(&CriticalSection);
    ClassMember = val;
    LeaveCriticalSection(&CriticalSection);
}

where "CriticalSection" is a CRITICAL_SECTION member of the STATE class that is of course initialised. The context in which I use these functions is:

NF3DGetEngineState()->Set(10);

The question is: is this code thread safe?

From what I learnt, returning references to static declarations is not thread safe.

What can I do to make it so?

featherless biped
  • 163
  • 1
  • 5
  • 16
  • 2
    Please explain why you think it's not thread safe – Sami Kuhmonen Oct 23 '15 at 12:20
  • I heard that returning references to static declarations is not thread safe? Am I right? – featherless biped Oct 23 '15 at 12:21
  • What are you doing with `ClassMember`? You need to use the same ressource protection while setting. – JeffRSon Oct 23 '15 at 12:21
  • I return it in other get-type functions that contain, in quite the same manner, a critical section lock-release mechanism. The difference is that EnterCriticalSection and LeaveCriticalSection are called in the constructor and destructor of a wrapper class that is always declared in that function. – featherless biped Oct 23 '15 at 12:25
  • 1
    The *first* call to NF3DGetEngineState() may not be thread-safe, depending on the compiler. But if you call it once in the main startup (before multiple threads try to access it), after that parallel calls will get the same instance. – birdypme Oct 23 '15 at 12:42

1 Answers1

4

Which is your C++ version? If it is C++11 or later, than the code is as thread safe as it gets. If it is pre-11, it is unsafe with regards to first call to NF3DGetEngineState.

Clarification.

It is not that returning references to static variables 'is not thread safe'. On the contrary, it is 100% safe. What is not thread-safe pre-C++11 is static variable initialization itself. pre-C++11 makes no guarantees in regards to the concurrent calls to the function for the first time. In fact, all pre-11 C++ compilers I worked with would have a problem if you concurrently enter this function for the first time. The reason is, the code which compiler generates when static variables are used, looks approximately like following:

static bool static_var_initialized = false; 
if (!static_var_initialized) {
    new (&static_var) StaticVarType(); // Explicit constructor call
    static_var_initialized = true;
}

Obviously, there is a possibility of calling constructor multiple times if you happen to call this function multiple times before static variable is set to true.

In C++11, there is a guarantee that it will never happen, and constructor will be called only once. It also guarantees no threads will see unconstructed value.

SergeyA
  • 61,605
  • 5
  • 78
  • 137