Baruch
Baruch

Reputation: 21508

Do global variable constructors/destructors need thread protection?

If I have a class whose sole purpose is to have global static instances (to ensure the code in it's constructor is run before main) and it uses a class static variable, does access to this variable need to be protected via mutex?

An example will help:

class WinSock
{
public:
  WinSock()
  {
    if(!(inst++))
      //winsock init
  }
  ~WinSock()
  {
    if(!--inst)
      //winsock deactivate
  }
private:
  static int inst = 0;
}
static WinSock unusedWinSockVar;

This is all in a header that is included by any file using winsock. Does access to inst need to be protected, or is it impossible for this code to be run from multiple threads since threads will be created only once main runs and destroyed before main returns?

Upvotes: 1

Views: 1223

Answers (2)

Damon
Damon

Reputation: 70136

Given the specific scenario that you describe, this is fine without adding synchronization.

Your concern is that Winsock is initialized (and de-initialized) before (after) main runs, this is guaranteed to be the case. The code is guaranteed to be only called once from one thread, too. This (the fact that there's only one thread) makes synchronization useless.

Assuming that other static global objects use Winsock (whether or not they spawn threads), that would of course be unsafe, but it wouldn't be any safer with a mutex either. The initialization takes place at an implementation-defined point in time before main.
Therefore, no static global object can use Winsock in a safe, well-defined way using this construct, since either way you don't know whether initialization occurred first. Synchronizing it doesn't change a thing for that detail.

Note: the initialization of inst inside the class declaration isn't allowed as it is.

Upvotes: 0

j_kubik
j_kubik

Reputation: 6181

Firstly, I don't think that private: static int inst = 0; is a valid construct, my compilers complains loudly - if you omitted that you have something like int WinSock::inst = 0 in some .cpp file in your project for simplicity, then it's ok. If not and your project compiles at all, there is a good chance that all translation units will use a different variable, and therefore result in incorrect behavior.

Secondly, if any of the static-object constructors creates a new thread, then you need to make your code thread safe. From C++ standard p. 3.6.2:

If a program starts a thread (30.3), the subsequent initialization of a variable is unsequenced with respect to the initialization of a variable defined in a different translation unit. Otherwise, the initialization of a variable is indeterminately sequenced with respect to the initialization of a variable defined in a different translation unit.

Indeterminate sequencing means that initialization will not have any particular ordering, but it will not overlap, so you don't need any additional safeguards. No ordering means that constructors in different compilation unis might overlap, and therefore thread safety is required.

Thirdly, do you even need it done like this? Do you have other static objects that use winsock in their constructors? I really cannot think of any other reason to do it like that.

Upvotes: 4

Related Questions