7

Given the following example:

struct test
{
    const char* data;
    const int number;
};

struct test* foo()
{
    static struct test t = {
        "this is some data",
        69
    };
    return &t;
}

is the call to foo thread safe? In other words, is the structure initialized only once in a thread-safe manner? Does it make a difference if this is compiled in C or C++?

cigien
  • 57,834
  • 11
  • 73
  • 112
fjanisze
  • 1,234
  • 11
  • 21
  • 1
    In C++ it's thread safe. I don't know about C. – Ted Lyngmo Feb 06 '23 at 07:30
  • 2
    Related: [Is local static variable initialization thread-safe in C++11?](https://stackoverflow.com/q/8102125/12149471) – Andreas Wenzel Feb 06 '23 at 07:34
  • 1
    The C and C++ initialization rules are quite different, so you should ask about one language at a time. – Lundin Feb 06 '23 at 07:42
  • 1
    @Lundin: On the other hand, having a question about the differences between both languages could be useful. However, this would require an answerer to know the rules of both languages. – Andreas Wenzel Feb 06 '23 at 07:44
  • 3
    In C++, the initialisation of `t` is thread safe since C++11. Before C++11, it was not thread safe (since earlier standards didn't have any provision related to threading at all). I *believe* the initialisation of `t` is also thread safe in C, mostly because static variables can only be initialised with literals (compile time constants) in C [from which I infer that the structure will be initialised before any thread ever accesses it]. – Peter Feb 06 '23 at 07:47
  • C doesn't have static initialization order or "static initialization fiascos". Nor does it have constructors or RAII. So this simply can't be thread unsafe in C. As for C++, they've made these rules quite complex post C++11. – Lundin Feb 06 '23 at 07:50
  • @AndreasWenzel Maybe but now 3 answers were posted and all are "wrong" since they do not address both languages. Bad questions lead to bad answers. – Lundin Feb 06 '23 at 07:54
  • It thread-safe in C++. Now someone just needs to post a combined C/C++ answer. – HolyBlackCat Feb 06 '23 at 07:54
  • The C++ part has several duplicates, so an answer could refer to that and focus on the C part. – nielsen Feb 06 '23 at 08:06
  • @Lundin regarding "can't be thread unsafe in C" - what about assigning a static with the result of e.g. `malloc` ? – wohlstad Feb 06 '23 at 10:55
  • @wohlstad That's a constraint violation, since function calls are not compile-time constants. Specifically C17 6.7.9 "All the expressions in an initializer for an object that has static or thread storage duration shall be constant expressions or string literals." – Lundin Feb 06 '23 at 11:02
  • @wohlstad C has been like that since the dawn of time, although C23 will bring a `constexpr` keyword giving some more options (not to be confused with C++). Also some [non-conforming compilers like gcc](https://stackoverflow.com/questions/68252570/why-are-const-qualified-variables-accepted-as-initializers-on-gcc) accept a few more options. – Lundin Feb 06 '23 at 11:12

2 Answers2

4

The distinction exists in C/C++ prior to C++ 11 and in C++ 11 or later (Earlier standards lacked any provisions for threading.).

As you can see here: C++ Static local variables, since C++11 is it guaranteed by the standard that a static local variable will be initialized only once. There is a specific note regarding locks that can be applied to ensure single initializing in a multi threaded environment:

If multiple threads attempt to initialize the same static local variable concurrently, the initialization occurs exactly once (similar behavior can be obtained for arbitrary functions with std::call_once). Note: usual implementations of this feature use variants of the double-checked locking pattern, which reduces runtime overhead for already-initialized local statics to a single non-atomic boolean comparison.

The rules in C are specified here: C Storage duration:

static storage duration. The storage duration is the entire execution of the program, and the value stored in the object is initialized only once, prior to main function. All objects declared static and all objects with either internal or external linkage that aren't declared _Thread_local (since C11) have this storage duration.

Amit
  • 645
  • 1
  • 3
  • 19
  • 1
    This answer may be correct for C++, but the question is also asking about the difference between the languages C and C++. – Andreas Wenzel Feb 06 '23 at 07:55
  • 1
    In my opinion, a complete answer should also specify the rules in C. The documentation page to which you linked contains at the bottom a link to the corresponding C documentation, which specifies the rules in C. Search for `"and the value stored in the object is initialized only once, prior to main function."` in the C documentation. – Andreas Wenzel Feb 06 '23 at 08:22
  • @AndreasWenzel, due to your 2 comments, I updated my answer. – Amit Feb 06 '23 at 08:47
  • 1
    You have now quoted the relevant rules of both languages. However, you have not directly answered the question. Does this mean that the initialization is thread-safe in both languages? If that is the case, then you may want to explicitly state it in the answer. – Andreas Wenzel Feb 06 '23 at 08:58
-1

Since C++11, object initialization will be made only by one thread, other threads will wait till it complete. See this thread for reference.

R3DC0DE
  • 19
  • 7
  • 1
    This answer may be correct for C++, but the question is also asking about the difference between the languages C and C++. – Andreas Wenzel Feb 06 '23 at 08:27