是setlocale线程安全的功能吗?

mil*_*ilo 9 c++ double parsing setlocale

我需要在线程中更改区域设置以正确解析带有strtod()的double,我正在使用setlocale()(C++).它是线程安全的吗?

更新:另一个问题.当我在main()函数中调用setlocale()时,它不会更深入地影响其他例程.为什么???有很多代码,所以编写块有问题.

Wic*_*man 7

对setlocale()的调用可能是也可能不是线程安全的,但是语言环境设置本身是按进程而不是每个线程.这意味着即使您的setlocale()是线程安全的,或者您使用互斥锁来保护自己,更改仍将更新所有线程的当前区域设置.

但是有一个每线程的替代方案:uselocale().

#include <xlocale.h>

locale_t loc = newlocale(LC_ALL_MASK, "nl_NL", NULL);
uselocale(loc);
freelocale(loc)
// Do your thing
Run Code Online (Sandbox Code Playgroud)

语言环境在内部使用引用计数,这就是为什么在使用newlocale()激活它之后释放它是安全的.


Car*_*ell 7

在C++ 11标准中,线程现在是该语言的受支持部分.该标准明确指出setlocale()调用引入了对setlocale()的其他调用的数据争用,或者调用受当前C语言环境影响的函数,包括strtod().locale :: global()函数被认为是行为 - 如果它调用了setlocale(),所以它也可以引入数据竞争(如下所述).

在使用glibc的Linux上,MT-unsafe(const:locale env)让线程与非NULL参数同时调用setlocale()并调用可能使用全局语言环境的任何其他函数(数据竞争,因此C11中的未定义行为) .建议使用uselocale()代替MT-safe并仅更改调用线程的语言环境.在使用C++代码中的libstdc ++的Linux上,您应该避免使用locale :: global(进程范围更改)并为线程的使用创建一个语言环境(locale :: global出于MT安全性的原因与C运行时相同).鉴于您的目标是使用strtod(C API),您应该使用uselocale().

在使用glibc的Linux上,setlocale()函数本身是MT不安全的,除非你满足2个严格的标准,并且根据POSIX的要求改变整个过程的语言环境.新的Linux手册页(Red Hat和Fujitsu的一部分用于为所有API指定MT安全符号)将setlocale()标记为"MT-Unsafe const:locale env",这意味着setlocale是您保留的MT安全IFF语言环境常量(通过不修改它,只是通过传递NULL来查询它),并且如果保持语言环境和环境不变(以避免在参数为""时更改语言环境).在使用glibc的Linux上,如果你想只改变调用线程的语言环境,你应该使用uselocale(),因为这是MT安全的,并且不以任何方式依赖你的环境,strtod将使用线程的语言环境.类似地,所有实现POSIX的系统都应该提供uselocale()以用于线程上下文(MT-safe).

OS X实现了uselocale(),因此您可以使用它.

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


pax*_*blo 3

无论您使用什么实现,您都需要查阅文档。C++ 目前没有指定任何有关线程的内容,因此它取决于实现(您还没有告诉我们)。

例如,我的 setlocale Linux 手册页包含以下代码片段:

该字符串可以分配在静态存储中。

这并不绝对表明它是线程不安全的,但我会非常警惕。用 NULL 调用它(即查询)很可能是线程安全的,但一旦有线程修改它,所有的赌注都会消失。

也许最安全的事情(假设它不是线程安全的)是使用setlocale互斥体保护所有调用,并使用一个特殊的函数来格式化您的数字:

claim mutex
curr = setlocale to specific value
format number to string
setlocale to curr
release mutex
return string
Run Code Online (Sandbox Code Playgroud)