简体   繁体   English

是setlocale线程安全的功能吗?

[英]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++). 我需要在线程中更改区域设置以正确解析带有strtod()的double,我正在使用setlocale()(C ++)。 Is it thread safe? 它是线程安全的吗?

Update: Another problem. 更新:另一个问题。 When I invoke setlocale() in my main() function it doesn't affect in other routines deeper. 当我在main()函数中调用setlocale()时,它不会更深入地影响其他例程。 Why??? 为什么??? There is a lot of code, so it's problematic to write the chunk. 有很多代码,所以编写块有问题。

In the C++11 standard threads are now a supported part of the language. 在C ++ 11标准中,线程现在是该语言的受支持部分。 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(). 该标准明确指出setlocale()调用引入了对setlocale()的其他调用的数据争用,或者调用受当前C语言环境影响的函数,包括strtod()。 The locale::global() function is considered to behave as-if it called setlocale(), so it also can introduce a data race (noted below). locale :: global()函数被认为是行为 - 如果它调用了setlocale(),所以它也可以引入数据竞争(如下所述)。

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). 在使用glibc的Linux上, MT-unsafe(const:locale env)使线程与非NULL参数同时调用setlocale()并调用可能使用全局语言环境的任何其他函数(数据竞争,因此在C11中未定义的行为) 。 It is suggested to use uselocale() instead which is MT-safe and changes only the calling thread's locale. 建议使用uselocale()代替MT-safe并仅更改调用线程的语言环境。 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). 在使用C ++代码中的libstdc ++的Linux上,您应该避免使用locale :: global(进程范围更改)并为线程的使用创建一个语言环境(locale :: global出于MT安全性的原因与C运行时相同)。 Given your goal to use strtod (a C API) you should use uselocale(). 鉴于您的目标是使用strtod(C API),您应该使用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. 在使用glibc的Linux上,setlocale()函数本身是MT不安全的,除非你满足2个严格的标准,并且根据POSIX的要求改变整个过程的语言环境。 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 ""). 新的Linux手册页( Red Hat和Fujitsu的一部分用于为所有API指定MT安全符号 )将setlocale()标记为“MT-Unsafe const:locale env”,这意味着setlocale是您保留的MT安全IFF语言环境常量(通过不修改它,只是通过传递NULL来查询它),并且如果保持语言环境和环境不变(以避免在参数为“”时更改语言环境)。 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. 在使用glibc的Linux上,如果你想只改变调用线程的语言环境,你应该使用uselocale(),因为这是MT安全的,并且不以任何方式依赖你的环境,strtod将使用线程的语言环境。 Similarly all systems that implement POSIX should provide uselocale() for use in a thread context (MT-safe). 类似地,所有实现POSIX的系统都应该提供uselocale()以用于线程上下文(MT-safe)。

OS X implements uselocale() so you can use that. OS X实现了uselocale(),因此您可以使用它。

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 . 在Windows上使用_configthreadlocale来更改setlocale()是否对整个进程或线程进行操作(将其转换为您需要的uselocale),但是对于C ++代码,您应该再次使用locale类的实例并避免使用locale :: global

The call to setlocale() may or may not be threadsafe, but the locale setting itself is per-process, not per-thread. 对setlocale()的调用可能是也可能不是线程安全的,但是语言环境设置本身是按进程而不是每个线程。 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. 这意味着即使您的setlocale()是线程安全的,或者您使用互斥锁来保护自己,更改仍将更新所有线程的当前区域设置。

There is a per-thread alternative though: uselocale(). 但是有一个每线程的替代方案: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(). 语言环境在内部使用引用计数,这就是为什么在使用newlocale()激活它之后释放它是安全的。

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). C ++目前没有指定任何关于线程的内容,所以它归结为实现(你还没有告诉我们)。

For example, my Linux manpage for setlocale has the snippet: 例如,我的s​​etlocale的Linux手册页有以下代码段:

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 (ie, querying) would be thread-safe but as soon as you have a thread modifying it, all bets are off. 可能是因为使用NULL调用(即查询)将是线程安全的,但只要你有一个线程修改它,全盘皆输。

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: 可能最安全的做法(假设它不是线程安全的)将保护所有使用互斥锁的setlocale调用,并具有一个特殊的函数来格式化你的数字:

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

For C++98 it depends on the compiler and on which runtime lib you select and on what exactly you mean by thread safe. 对于C ++ 98,它取决于编译器以及您选择的运行时库以及线程安全的确切含义。

Eg with MSVC and multi-threaded runtime you should be safe in the sense that setlocale itself is. 例如,对于MSVC和多线程运行时,从setlocale本身来看,你应该是安全的。 But I don't think you'll get a per-thread locale. 但我认为你不会得到一个每线程的语言环境。 Use setlocale for a global locale, not a per-thread locale. setlocale用于全局区域设置,而不是每线程区域设置。

C++98 does not address threading (or, for that matter, dynamic libraries). C ++ 98不涉及线程(或者,就此而言,动态库)。

C language does support thread local. C语言支持本地线程。 Please read http://msdn.microsoft.com/en-us/library/ms235302.aspx . 请阅读http://msdn.microsoft.com/en-us/library/ms235302.aspx The main methods is: _configthreadlocale(_ENABLE_PER_THREAD_LOCALE) 主要方法是:_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. setlocale函数位于C库中(由标准头<clocale>在C ++环境中定义),其使用仅影响C库例程。 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 . 你在问题的第一部分提到了C ++,所以我想知道你是否期望C ++例程注意到用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> . 在C ++中处理语言环境信息的正确方法是由标准C ++标头<locale>指定的库定义的。 This library provides control of locale information in a way which is compatible with C++ I/O operations. 该库以与C ++ I / O操作兼容的方式提供对区域设置信息的控制。 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. 例如,您可以创建具有某些特征的std::locale对象,然后将std::filebuf与该对象一起使用,以便I / O操作遵循这些特性。

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. 如果您在混合C / C ++环境中运行,请使用std::locale::global() - 使用正确的参数类型,它还将C全局语言环境设置为使用LC_ALL调用C库函数setlocale This will keep the C and C++ library functionality synchronized. 这将使C和C ++库功能保持同步。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM