7

I am trying to understand a potential scenario and whether it is likely to be a problem.

So I have a static function that is currently thread-safe. The function being like so:

static thread_safe_func()
{
    ... process
}

Now in this function, I add the following:

static thread_safe_func()
{
  static const Class::NonThreadSafeClassName() *array[16] = {
    Class::NonThreadSafeClassName(),
    Class::NonThreadSafeClassName(),
    Class::NonThreadSafeClassName(),
    Class::NonThreadSafeClassName(),
    Class::NonThreadSafeClassName(),
    Class::NonThreadSafeClassName(),
    Class::NonThreadSafeClassName(),
  }
  ... code continues here
}

Now is it in itself thread-safe? The array will be initialized once for the entire duration of the application's life, so once the function thread_safe_func() has been called, and fully run, I would expect this to be thread-safe.

The issue is obviously what could occur during the first calls, what would happen in a scenario where a thread calls thread_safe_func(), the initialization of the const array occurs, but before that initialization completes, another thread is calling thread_safe_func().

Would a change to:

static ClassMutex lock = ClassMutex()

static thread_safe_func()
{
  lock.Lock()
  static const Class::NonThreadSafeClassName() *array[16] = {
    Class::NonThreadSafeClassName(),
    Class::NonThreadSafeClassName(),
    Class::NonThreadSafeClassName(),
    Class::NonThreadSafeClassName(),
    Class::NonThreadSafeClassName(),
    Class::NonThreadSafeClassName(),
    Class::NonThreadSafeClassName(),
  }
  lock.Unlock()
  ... code continues here
}

be worthwhile and guarantee that this code is now thread-safe?

squelart
  • 11,261
  • 3
  • 39
  • 43
jyavenard
  • 2,142
  • 1
  • 26
  • 35
  • 1
    Your example code does not look valid to me. Then it's meaningless to ask whether it's thread safe. – Cheers and hth. - Alf Mar 04 '12 at 22:30
  • Please post something that's at least syntactically valid C++, and keep the presentation simple and to the point. – Kerrek SB Mar 04 '12 at 22:31
  • 1
    With the advent of c++11 there is no longer a need to lock around the static initialization: it is threadsafe by definition in the standard – sehe Mar 04 '12 at 22:32
  • 1
    ignore this comment, can't delete on my phone for some reason. – Nim Mar 04 '12 at 22:33
  • 1
    @Cheersandhth.-Alf: of course it's not valid C++ code. That's not the point.. It is about discussing a concept, not how something is syntactically correct! You do understand the meaning of concept do you? – jyavenard Mar 04 '12 at 22:42
  • My compiler doesn't, it is easy to check by looking at the generated code. There's already a raft of low-level locking going on most practical standard library implementations to make it compatible with modern times, the buck stops somewhere. Definitely at the compiler having knowledge of OS implementation details. – Hans Passant Mar 04 '12 at 22:44

1 Answers1

6

Under C++03, neither...

void foo() {
  static your_variable = ...;
}

...nor...

void foo() {
    lock.Lock();
    static your_variable = ...;
    lock.Unlock();
}

...are thread safe.

The first one is not thread safe because standard says nothing about second thread entering the function while the first thread is still performing the initialization. In fact, standard has no notion of threads at all.

The second one is not thread safe because the initialization happens when the flow of execution enters the function (for the first time), which is before lock.Lock().


In C++11, initialization of the local static variable is thread safe.

Community
  • 1
  • 1
Branko Dimitrijevic
  • 50,809
  • 10
  • 93
  • 167
  • 2
    Additional info on the second point, from the spec (section 6.7): "Constant initialization (3.6.2) of a local entity with static storage duration, if applicable, is performed before its block is first entered." – user1201210 Mar 05 '12 at 00:41
  • 2
    But `void foo() { lock.Lock(); {static your_variable = ...;} lock.Unlock(); }` is safe? – qehgt Mar 05 '12 at 00:47
  • 1
    @qehgt I _believe_ it would be safe even in C++03. However, if `foo` is called during static initialization of global variables, there is no guarantee the `lock` is initialized yet, which defeats one of the [main usage scenarios](http://stackoverflow.com/a/1005709/533120) for local static variables. You could wrap the `lock` in another function, but this just moves the problem elsewhere without actually solving it... – Branko Dimitrijevic Mar 05 '12 at 01:14
  • Thanks @BrankoDimitrijevic, this is exactly what I was looking for. qhgt's suggestion would sufficiently alleviate the problem I believe. – jyavenard Mar 05 '12 at 01:27