60

In the example code

void foo()
{
  static Bar b;
  ...
}

compiled with GCC is it guaranteed that b will be created and initialized in a thread-safe manner ?

In gcc's man page, found the -fno-threadsafe-statics command line option:

Do not emit the extra code to use the routines specified in the C++ ABI for thread-safe initialization of local statics. You can use this option to reduce code size slightly in code that doesn't need to be thread-safe.

  1. Does it mean, that local statics are thread-safe by default with GCC ? So no reason to put explicit guarding e.g. with pthread_mutex_lock/unlock ?

  2. How to write portable code - how to check if compiler will add its guards ? Or is it better to turn off this feature of GCC ?

Daniel Kamil Kozar
  • 16,009
  • 5
  • 43
  • 61
CsTamas
  • 3,803
  • 5
  • 28
  • 34

4 Answers4

44
  1. No, it means that the initialization of local statics is thread-safe.

  2. You definitely want to leave this feature enabled. Thread-safe initialization of local statics is very important. If you need generally thread-safe access to local statics then you will need to add the appropriate guards yourself.

CB Bailey
  • 648,528
  • 94
  • 608
  • 638
  • 2
    what use is thread-safe initialization if you don't have thread-safe (local function) access? – xtofl Aug 13 '09 at 09:31
  • 10
    To initialize the mutex you'll use to control access to other variables. – AProgrammer Aug 13 '09 at 09:34
  • 6
    If you have to write portable code, you can not rely on thread safe initialization of function statics. For example MS C++ doesn't do it. So I disagree on point 2 - you can safely disable it, if you want to write portable code, but you must not use function statics where thread safety is important ;-) – Gunther Piez Aug 13 '09 at 09:41
  • @xtofl: What AProgrammer says! Typically, it requires less code to check whether a `static` has been initialized, and initialize it just once in a thread safe manner than it is to provide general thread-safe access. It's also something the compiler pretty much has to do for you. If you couldn't guarantee that two threads wouldn't cause the 'same' mutex to be initialized simultaneously you'd be in a pretty hard place. – CB Bailey Aug 13 '09 at 09:42
  • 4
    @xtofl: If you have a singleton like this `class singleton { static singleton& get() {static singleton s; return s} };`, the fact that the singleton must be thread safe is an issue orthogonal to the fact that its initialization must be thread-safe, too. – sbi Aug 13 '09 at 09:47
  • I have some difficulty understanding the difference between initialization and access: does 'safe init' mean that two threads executing `void foo() { static int i = 10; cout< – xtofl Aug 13 '09 at 10:55
  • 2
    @xtofl: Safe initialization means that e.g. if you have `static Obj o;`, then the constructor for o will only be called once even if two threads call the function for the first time at (almost) the same time. Also, neither thread should be able to use `o` until the construction of `o` is complete. The same applies conceptually to basic types, but an object type makes it more obvious. Thread safe static initialization doesn't imply that there's any synchronization for further use of the object in the function body. – CB Bailey Aug 13 '09 at 11:04
  • @drhirsch: Because making it thread safe is platform specific you will need to use macros anyway. So this just makes the GCC macros empty (thus less to debug). – Martin York Aug 13 '09 at 17:16
18

We had serious issues with the locking code generated by GCC 3.4 to protect local static initialization. That version used a global shared mutex to protect all and any static initialization which lead to a deadlock in our code. We had a local static variable initialized from a result of a function, which started another thread, which created a local static variable. Pseudocode:

voif f()
{
  static int someValue = complexFunction();
  ...
}
int complexFunction()
{
  start_thread( threadFunc() );
  wait_for_some_input_from_new_thread();
  return input_from_new_thread;
}
void threadFunc()
{
  static SomeClass s();
  ...
}

The only solution was to disable this feature of gcc. If you need your code to be portable , which we did, you can not anyway depend on a feature added in a specific gcc version for thread safety. Supposedly C++0x adds thread-safe local statics, until then this is non-standard magic which makes your code non-portable, so I am advising against it. If you decide to use it, I suggest you validate that your gcc version does not use a single global mutex for this purpose by writing a sample application. (The difficulty of thread-safety is apparent from the fact that even gcc can not get it right)

Thanatos
  • 37,926
  • 14
  • 76
  • 136
shojtsy
  • 1,620
  • 2
  • 17
  • 23
6

This is not really answering your questions straight away (Charles already did that), but I think it's time to post a link to this article again. It throws light on the initialization of globals and should be read and understood by everyone attempting to use static variables in a multi-threaded environment.

Community
  • 1
  • 1
sbi
  • 204,536
  • 44
  • 236
  • 426
5

I think that the key phrase is

... thread-safe initialization of local statics.

I read this as meaning that it is only initialization of statics that would be done in a thread-safe way. General use of statics would not be thread-safe.

Stephen C
  • 632,615
  • 86
  • 730
  • 1,096