2

I am implementing something very similar to the question here.

Window::Window()
{
  static bool flagInit = true;
  if (flagInit)
  {
    doInit(); // doInit should be called only once. 
    flagInit = false;
  }  
  createWindow()
}

I understand that using static variables can generally be a bad idea when it comes to multithreading. If two threads create Window instance at the same time, flagInit might fail to work due to data race. But Singleton class won't do me the job either, since I want to create multiple instance of the class.

Window toolTip, mainWindow;

If I add a mutex to the initialization part, does that make it thread safe? Also, is that a good pratice to do so?

Window::Window()
{
  {
    std::scoped_lock<std::mutex> lock(mutex);
    static bool flagInit = true;
    if (flagInit)
    {
      doInit(); // doInit should be called only once. 
      flagInit = false;
    }  
  }
  createWindow()
}

PS doInit() comes from someone else's library so I cannot do anything to it

charliepu123
  • 59
  • 1
  • 7
  • Re, "static variables can...be a bad idea when it comes to multithreading." Not _only_ in multi-threaded programs. Static variables also are a hinderance to testing and, to re-useability. I personally use static variables only when I am _forced_ to do so (e.g., in an embedded system where I am prohibited from using the heap) or, in projects so small and so short-lived that I would not be sad if I lost the source code. – Solomon Slow Jun 11 '20 at 12:58

1 Answers1

4

There's a tool exactly for this: std::call_once:

class Window
{
  static std::once_flag flagInit;
  // ...
};

Window::Window()
{
  std::call_once(flagInit, doInit); // Note: can throw
  createWindow();
}

You can also technically still accomplish this with statics since C++11 made their initialization thread-safe:

Window::Window()
{
  static bool flagInit = (doInit(), false);
  createWindow()
}
chris
  • 60,560
  • 13
  • 143
  • 205
  • Thank you for your kind help! Both ways seem very elegant to me. For `static bool flagInit = doInit(), false;` I am not familiar with the grammar here. Could you throw me a link maybe? – charliepu123 Jun 11 '20 at 05:41
  • 1
    @charliepu123, It's using the [comma operator](https://stackoverflow.com/questions/52550/what-does-the-comma-operator-do). You need some kind of value there because it's initialization, but `doInit` could return `void`, so this ensures there's _some_ value. The type and actual value don't matter since you'll never need to use that variable after. With that said, in C++17, I'd personally go for `[[maybe_unused]] static bool _ = doInit(), false;` or something similar since it puts aside the name and makes it clear the variable is deliberate. – chris Jun 11 '20 at 05:44