Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is setlocale thread-safe function?

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.

like image 862
milo Avatar asked Oct 30 '10 04:10

milo


2 Answers

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.

like image 85
Carlos O'Donell Avatar answered Sep 20 '22 00:09

Carlos O'Donell


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().

like image 28
Wichert Akkerman Avatar answered Sep 22 '22 00:09

Wichert Akkerman