更新:另一个问题。当我在main()函数中调用setlocale()时,它不会影响更深层次的其他例程。为什么?由于代码很多,所以编写代码块有问题。
在 C++11 标准中,线程是语言的一部分。标准明确指出,setlocale() 调用会与其他调用 setlocale() 或调用受当前 C 语言环境影响的函数引入数据竞争,包括 strtod()。locale::global() 函数被认为与 setlocale() 齐名,因此也可能导致数据竞争(如下所示)。
在 Linux 上,使用 glibc 来说,当线程并发调用 setlocale() 并带有非空参数,并调用可能使用全局语言环境的任何其他函数时,这种情况是 MT-unsafe (const:locale env) 的,这会导致数据竞争并引起未定义行为。建议改用只更改调用线程语言环境且是 MT-safe 的 uselocale()。在 C++ 代码中,如果在 Linux 上使用 libstdc++,应避免 locale::global (进程范围更改),而应为线程创建语言环境(由于与 C 运行时相同的原因,locale::global 是 MT-unsafe)。鉴于您的目标是使用 strtod(C API),应使用 uselocale()。
在Linux上,使用glibc时,setlocale()函数本身是MT-unsafe的,除非你满足两个严格的条件,并且根据POSIX的要求,会改变整个进程的语言环境。新的Linux man页面(Red Hat和Fujitsu致力于为所有API指定MT-safety注释的一部分)将setlocale()标记为“MT-Unsafe const:locale env”,这意味着只有在保持语言环境恒定(通过不修改它,仅通过传递NULL查询它),并且保持语言环境和环境恒定(以避免参数为""时更改语言环境)的情况下,setlocale才是MT-safe的。在Linux上,如果您想仅更改调用线程的语言环境,则应使用uselocale(),因为这是MT-safe的,而且不以任何方式依赖于您的环境,strtod将使用线程的语言环境。同样,所有实现POSIX的系统都应该提供uselocale()供在线程上下文中使用(MT-safe)。调用setlocale()函数可能是线程安全的,也可能不是,但是区域设置本身是每个进程而非每个线程的。这意味着即使你的setlocale()是线程安全的或者你使用互斥锁来保护自己,改变仍将更新所有线程的当前区域设置。
不过,有一种针对每个线程的替代方法:uselocale()。
#include <xlocale.h>
locale_t loc = newlocale(LC_ALL_MASK, "nl_NL", NULL);
uselocale(loc);
freelocale(loc)
// Do your thing
locale在内部使用引用计数,这就是为什么在您使用newlocale()激活它后可以安全释放它的原因。
setlocale
调用的最安全的事情(假设它不是线程安全的)可能是使用互斥锁保护所有调用,并具有类似以下内容的特殊函数来格式化您的数字:claim mutex
curr = setlocale to specific value
format number to string
setlocale to curr
release mutex
return string
setlocale
本身一样。但我认为您不会得到每个线程的区域设置。请使用 setlocale
设置全局区域设置,而不是每个线程的区域设置。C++98 不涉及线程(或动态库)问题。回答原问题的第二个部分:
setlocale
函数在C库中(在标准头文件<clocale>
中定义在C++环境中),使用它只会影响C库例程。你在问题的第一部分提到了C ++,我想知道您是否希望C ++例程注意使用setlocale
进行区域设置更改。我的经验表明他们不会。
C++处理区域信息的正确方法是由标准C++头文件<locale>
中指定的库定义的。该库以与C++ I/O操作兼容的方式控制区域信息。例如,您可以创建具有某些特征的std::locale
对象,然后用该对象灌输一个std::filebuf
,以便I/O操作遵循这些特征。
如果您正在运行混合的C / C ++环境,请使用std::locale :: global()
- 使用正确类型的参数,它还将设置C全局区域设置,就像调用LC_ALL的C库函数setlocale
一样。这将使C和C ++库功能保持同步。