views:

218

answers:

5

Hi all, I'm wondering whether static constant variables are thread-safe or not?

Example code snippet:

void foo(int n)
{
     static const char *a[] = {"foo","bar","egg","spam"};
     if( ... ) {
       ...
      }
}
+6  A: 

In your example the pointer itself can be considered as thread safe. It will be initialized once and won't be modified later.

However, the content of the memory pointed won't be thread-safe at all.

Grimmy
Assuming no programming errors causing buffer over-run or under-run, what's the premise for the memory not being thread-safe?
Lazarus
Concurrent access to a shared resource (in this case, memory) can lead to some corruption or undesired behavior. To avoid that kind of issue, access to that resource must be serialized somehow. Usually this can be achieved using mutexes or any higher-level objects such as critical section. For more info, here a couple of interesting information: http://www.c2.com/cgi/wiki?ThreadSafe http://en.wikipedia.org/wiki/Thread_safety
Grimmy
The pointers *can* be modified. The chars in the actual strings can't.
Matthew Flaschen
@Grimmy: That's only writing. Multiple threads can read any given block of memory simultaneously with no issue. In this case, if all the data is const (the pointer and the contents), then there is no thread safety issue- if he ensures that it's only initialized once.
DeadMG
-1 const foo* means that the pointer points to a foo that can't be changed, *not* that the pointer itself can't be changed.
JeremyP
+3  A: 

In this example, a is not const. It's an array of pointers to const strings. If you want to make a itself const, you need:

static const char *const a[] = {"foo","bar","egg","spam"};

Regardless of whether it's const or not, it's always safe to read data from multiple threads if you do not write to it from any of them.

As a side note, it's usually a bad idea to declare arrays of pointers to constant strings, especially in code that might be used in shared libraries, because it results in lots of relocations and the data cannot be located in actual constant sections. A much better technique is:

static const char a[][5] = {"foo","bar","egg","spam"};

where 5 has been chosen such that all your strings fit. If the strings are variable in length and you don't need to access them quickly (for example if they're error messages for a function like strerror to return) then storing them like this is the most efficient:

static const char a[] = "foo\0bar\0egg\0spam\0";

and you can access the nth string with:

const char *s;
for (i=0, s=a; i<n && *s; s+=strlen(s)+1);
return s;

Note that the final \0 is important. It causes the string to have two 0 bytes at the end, thus stopping the loop if n is out of bounds. Alternatively you could bounds-check n ahead of time.

R..
Why can't compilers put such data in constant sections? The bit-for-bit values of the array items won't be known until load time, but the loader should have no trouble filling stuff in. Is the issue with systems that expect constant sections to be relocatable even during code execution?
supercat
I don't call it a constant section if it's modified by the loader at load-time. It incurs a physical memory hit for every process that uses the library and significant load-time overhead. By actual constant sections, I meant shared memory-mapped images of the actual library file on disk. If you think I should clarify that in the answer, I will.
R..
+9  A: 

To be really safe you should do

static char const*const a[]

this inhibits modification of the data and all the pointers in the table to be modified.

BTW, I prefer to write the const after the typename such that it is clear at a first glance to where the const applies, namely to the left of it.

Jens Gustedt
+8  A: 

Any variable that is never modified, whether or not it's explicitly declared as const, is inherently thread-safe.

Ferruccio
+1 for simplicity and correctness.
R..
+1  A: 

static const char *a[] = {"foo","bar","egg","spam"};

In C that would be always thread safe: the sructures would be already created at compile time, thus no extra action is taken at run time, thus no race condition is possible.

Beware the C++ compatibility though. Static const object would be initialized on the first entry into the function, but the initialization is not guaranteed to be thread-safe by the language. IOW this is open to a race condition when two different threads come into the function simultaneously and try to initialize the object in parallel.

But even in C++, POD (plain old data: structures not using C++ features, like in your example) would behave in the C compatible way.

Dummy00001
at any time one of the threads could do e.g `a[0] = "faa"`, so no, this is only threadsafe if you give some extra guarantees, but this is not threadsafe per se.
Jens Gustedt
@Jens Gustedt: true, but my reading of the question is whether the initialization is thread safe. Initialization is. Usage - usual rules apply.
Dummy00001