9

In C++11, the following is thread-safe:

void someFunc()
{
    static MyObject object;
}

But what about

void someFunc()
{
    static MyObject *ptr = new MyObject();
}

Is this then thread-safe or not?

As it was mentioned in the comments by @Nawaz, it is possibile, that the MyObject constructor isn't thread-safe, so let's divide the question into parts:

1) If the ctor is thread-safe (it doesn't access any shared state), is this static MyObject *ptr = new MyObject(); thread-safe? In other words, is static int *ptr = new int(0); thread-safe?

2) If the ctor isn't thread-safe, but the object is created only by calling someFunc from different threads, and the constructor is never used from anywhere else, will this be thread-safe then?

Vladimir
  • 279
  • 1
  • 11
  • 4
    `static MyObject object;` is **not** thread-safe IF the default constructor is not thread-safe, i.e if it accesses a mutable shared resource internally, say through global variables or singletons. However, `static int object = 100;` is 100% thread-safe. – Nawaz Jul 24 '14 at 12:24
  • 1
    @Nawaz Considering the quote you gave in the comment to my (now deleted) answer, wouldn't it indicate that both initializations are in fact thread-safe? (The quote in question is "*If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.*", from the C++11 specification §6.7/4). – Some programmer dude Jul 24 '14 at 12:44
  • 1
    @JoachimPileborg: I don't think so. The Standard guarantees only this : if more one thread attempts to start executing the constructor concurrently, only one of them will actually execute it, the rest will wait for the completion of initialization. The Standard, however, doesn't give any guarantee of the thread-safety of the constructor itself. It is quite possible the constructor itself is thread-unsafe (if it accesses *modifiable* global resource, for example). – Nawaz Jul 24 '14 at 12:48
  • @Nawaz In other words, we are guaranteed that the actual initialization is thread-safe, but not that multiple threads causes reinitialization? – Some programmer dude Jul 24 '14 at 12:53
  • Only one thread will initialise `object`, but `object`'s constructor might not be thread-safe. – Simple Jul 24 '14 at 12:59
  • @JoachimPileborg: I didn't understand what you mean by *"actual initialization"* (being *"thread-safe"*?). Well, the Standard doesn't say anything more than "a constructor is guaranteed to be executed non-concurrently". That alone cannot be a guarantee of thread-safety. For a constructor to be thread-safe, it must *not* access modifiable *unprotected* shared data. – Nawaz Jul 24 '14 at 13:00
  • @Nawaz I think we're saying the same thing, just with different words. :) – Some programmer dude Jul 24 '14 at 13:03
  • @Nawaz, thanks for pointing out the problem with ctor. I edited the question now. – Vladimir Jul 24 '14 at 13:06

1 Answers1

9

Yes, it is thread-safe. This follows from the same guarantee that applies to the first example, which is that concurrent executions of the function will initialize the static variable exactly once. Since the static pointer must be initialized exactly once, and the way to initialize it is defined as a call to new, then new and the constructor it invokes will each be called exactly once. Assuming that the constructor of the new object does not do anything unsafe, the whole thing will be safe.

Thanks to Matthieu M. for pointing out one exception: if the initialization throws, it will be attempted again by the next (pending or future) invocation of the function. It's still thread-safe though, because the second attempt will not begin until after the first one failed.

That being said, it's worrisome to see such code, because it seems likely to result in a memory leak which may be flagged by automated tools like valgrind, so it would be better to avoid this somehow. Even a class with a static member might be better, in that it would then be easier to clean up the static with a special method to be invoked before the program ends.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • 3
    Note: actually, the *exactly once* is wrong. It's *one at a time*, but the expression might be evaluated several times (successively) until it succeeds => in case of exception during the initialization, the object is known not to be initialized and initialization is attempted again next time control-flow passes through the definition. – Matthieu M. Jul 24 '14 at 13:18
  • Are the `static`s then execute under a global lock of some sort? Would they each have a lock of there own or a single lock? – Niall Jul 24 '14 at 13:40
  • John, your answer is exactly what I wanted to know, and I'll accept it. But it looks like @MatthieuM. is right in his comment, I just read this somewhere over the web. Maybe, you will edit your answer to make things more clear for future readers? – Vladimir Jul 24 '14 at 13:54
  • 1
    @Niall, yes, there is a lock there, [read Using a C++11 Static Initializer section](http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/). – Vladimir Jul 24 '14 at 14:06