Question

I need to change locale in the thread to parse a double with strtod() correctly, I'm using setlocale() for this (C++). Is it thread safe?

Update: Another problem. When I invoke setlocale() in my main() function it doesn't affect in other routines deeper. Why??? There is a lot of code, so it's problematic to write the chunk.

Was it helpful?

Solution

You need to consult the documentation for whatever implementation you're using. C++ doesn't currently specify anything about threads so it comes down to the implementation (which you haven't yet told us).

For example, my Linux manpage for setlocale has the snippet:

This string may be allocated in static storage.

which doesn't absolutely indicate that it's thread-unsafe but I'd be very wary. It's likely that calling it with NULL (i.e., querying) would be thread-safe but as soon as you have a thread modifying it, all bets are off.

Probably the safest thing to do (assuming it isn't thread-safe) would be to protect all calls to setlocale with a mutex and have a special function to format your numbers along the lines of:

claim mutex
curr = setlocale to specific value
format number to string
setlocale to curr
release mutex
return string

OTHER TIPS

The call to setlocale() may or may not be threadsafe, but the locale setting itself is per-process, not per-thread. That means that even if you setlocale() is thread-safe or you use a mutex to protect yourself, the change will still update the current locale for all your threads.

There is a per-thread alternative though: uselocale().

#include <xlocale.h>

locale_t loc = newlocale(LC_ALL_MASK, "nl_NL", NULL);
uselocale(loc);
freelocale(loc)
// Do your thing

The locale uses reference-counting internally, which is why it is safe for you to free it after you've activated it with newlocale().

In the C++11 standard threads are now a supported part of the language. The standard explicitly calls out that setlocale() calls introduce data races with other calls to setlocale() or calls to functions that are affected by the current C locale including strtod(). The locale::global() function is considered to behave as-if it called setlocale(), so it also can introduce a data race (noted below).

On Linux with glibc it is MT-unsafe (const:locale env) to have threads call setlocale() concurrently with a non-NULL argument and call any other function which might use the global locale (data race and thus undefined behaviour in C11). It is suggested to use uselocale() instead which is MT-safe and changes only the calling thread's locale. On Linux with libstdc++ in C++ code you should avoid locale::global (process wide change) and create a locale for the thread's use (the locale::global is MT-unsafe for the same reasons as the C runtime). Given your goal to use strtod (a C API) you should use uselocale().

On Linux using glibc the setlocale() function itself is MT-unsafe unless you meet 2 strict criteria, and as required by POSIX changes the locale for the entire process. The new Linux man pages (part of the Red Hat and Fujitsu work to specify MT-safety notations for all APIs) mark setlocale() as "MT-Unsafe const:locale env", which means that setlocale is MT-safe IFF you keep the locale constant (by not modifying it, just querying it by passing NULL), and if you keep the locale and environment constant (to avoid changes to the locale if the argument is ""). On Linux using glibc you should use uselocale() if you want to change just the locale of the calling thread, since this is MT-safe and does not rely on your environment in any way and strtod will use the thread's locale. Similarly all systems that implement POSIX should provide uselocale() for use in a thread context (MT-safe).

OS X implements uselocale() so you can use that.

On Windows use _configthreadlocale to change if setlocale() operates on the whole process or threads (turns it into uselocale which is what you need), but for C++ code you should again use an instance of the locale class and avoid locale::global.

For C++98 it depends on the compiler and on which runtime lib you select and on what exactly you mean by thread safe.

E.g. with MSVC and multi-threaded runtime you should be safe in the sense that setlocale itself is. But I don't think you'll get a per-thread locale. Use setlocale for a global locale, not a per-thread locale.

C++98 does not address threading (or, for that matter, dynamic libraries).

C language does support thread local. Please read http://msdn.microsoft.com/en-us/library/ms235302.aspx. The main methods is: _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)

To address the second part of the original question:

The setlocale function is in the C library (as defined in a C++ environment by the standard header <clocale>) and its use will only affect C library routines. You mention C++ in in the first part of your question, so I wonder if you are expecting C++ routines to take note of locale changes made with setlocale. My experience says they will not.

The proper methods of dealing with locale information in C++ are defined by a library specified in the standard C++ header <locale>. This library provides control of locale information in a way which is compatible with C++ I/O operations. For example, you can create a std::locale object with certain characteristics and then imbue a std::filebuf with that object so that I/O operations follow those characteristics.

If you are running in a mixed C/C++ environment, use std::locale::global() -- with the right sort of parameter, it also sets the C global locale as if the C library function setlocale was called with LC_ALL. This will keep the C and C++ library functionality synchronized.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top