开发者

STL objects use C Runtime Library locale for floating point conversion, when using _ENABLE_PER_THREAD_LOCALE?

开发者 https://www.devze.com 2023-01-24 04:19 出处:网络
The C Runtime locale is set by setlocale. The Standard C++ Library (STL) locale is set by the std::locale class and can be set on individual STL objects like std::istringstream etc.

The C Runtime locale is set by setlocale. The Standard C++ Library (STL) locale is set by the std::locale class and can be set on individual STL objects like std::istringstream etc.

The function _configthreadlocale(_ENABLE_PER_THREAD_LOCALE) allows setting the C Runtime locale on a per thread basis.

Unfortunately it seems that STL objects in threads where _configthreadlocale(_ENABLE_PER_THREAD_LOCALE) is enabled is using the C Runtime locale. Or at least using the decimal point of the C Runtime locale.

In threads without _ENABLE_PER_THREAD_LOCALE there are no problems.

Something similar was asked by 开发者_运维百科Paavo in 2008, but with no answers: _configthreadlocale and localeconv

The following code shows the problem:

//Enable per thread locale in current thread  
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE)  

//Create istringstream object  
std::istringstream LibraryStream;  
//Create double object  
double Value = 0;  
//Create std::locale object with "C" locale ("." as decimal point)  
std::locale StreamLoc("C");  
//Set C Runtime locale to danish ("," as decimal point)  
setlocale(LC_ALL, "danish");  

//Set the "C" locale on the istringstream object  
LibraryStream.imbue(StreamLoc);  
//Get the locale of the istringstream object for test (returns "C" as expected)  
std::locale NewStreamLoc = LibraryStream.getloc();  

//Set floating point string with "C" locale decimal point in istringstream object  
LibraryStream.str("60.258351");  
//Convert the string to double  
LibraryStream >> Value;  

//Now the expected value of "Value" is 60.258351, but it is 60.000  
//when debugging the conversion, I can see that "," is used as decimal point  

Have anyone experienced this before? Am I doing something wrong? Are there any suggestions for solutions?

Thanks in advance /TEB


Since C++ Standard Library only recently gained knowledge of threads, this apparent dichotomy does not surprise me. There is an exhaustive discussion of what happens in different scenarios (Microsoft-specific, but seems to be helpful as general background) here.

In summary:

To change the locale using the C++ Runtime Library, use the locale Class. By calling the locale::global method, you change the locale in every thread that has not explicitly enabled per-thread locale. To change the locale in a single thread or portion of an application, simply create an instance of a locale object in that thread or portion of code.


Disclaimer: I am not an expert at locales, so this may be wrong.

On the Multithreading and Locales Knowlegde Base article it is noted:

Calling locale::global changes the locale for both the Standard C++ Library and the C Runtime Library. However, calling setlocale only changes the locale for the C Runtime Library; the Standard C++ Library is not affected.

You are indeed using the C++ Std Lib, so it seemed to me that you needed to call locale::global(). When I did this, the return value is as you expected. Here is my sample code:

#include <cstdlib>
#include <locale>
#include <sstream>
using namespace std;

int main()
{

    //Enable per thread locale in current thread  
    int n = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)  ;

    //Create istringstream object  
    std::istringstream LibraryStream;  
    //Create double object  
    double Value = 0;  
    //Create std::locale object with "C" locale ("." as decimal point)  
    std::locale StreamLoc("C");  
    //Set C Runtime locale to danish ("," as decimal point)  
    char* ret = setlocale(LC_ALL, "danish");  

    //Set the "C" locale on the istringstream object  
    LibraryStream.imbue(StreamLoc);  
    locale::global(StreamLoc);
    //Get the locale of the istringstream object for test (returns "C" as expected)  
    std::locale NewStreamLoc = LibraryStream.getloc();  

    //Set floating point string with "C" locale decimal point in istringstream object  
    LibraryStream.str("60.258351");  
    //Convert the string to double  
    LibraryStream >> Value;  

        //Now the expected value of "Value" is 60.258351, but it is 60.000  
    //when debugging the conversion, I can see that "," is used as decimal point  
}


Good point John Dibling. I have tested that and the operator>> Value does use the locale in the stream and not the global locale. It was tested by the example below:

_configthreadlocale(_ENABLE_PER_THREAD_LOCALE), removed
locale::global(locale("danish"));, added to set the global Std lib locale

#include <cstdlib>
#include <locale>
#include <sstream>
using namespace std;

int main()
{
    //Enable per thread locale in current thread  
    //int n = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)  ;

    //Create istringstream object  
    std::istringstream LibraryStream;  
    //Create double object  
    double Value = 0;  
    //Create std::locale object with "C" locale ("." as decimal point)  
    std::locale StreamLoc("C");  
    //Set C Runtime locale to danish ("," as decimal point)  
    char* ret = setlocale(LC_ALL, "danish");

    //Set Std lib global locale to "danish"
    locale::global(locale("danish"));

    //Set the "C" locale on the istringstream object  
    LibraryStream.imbue(StreamLoc);  

    //Get the locale of the istringstream object for test (returns "C" as expected)  
    std::locale NewStreamLoc = LibraryStream.getloc();  

    //Set floating point string with "C" locale decimal point in istringstream object  
    LibraryStream.str("60.258351");  
    //Convert the string to double  
    LibraryStream >> Value;  

    //In this case the value of "Value" is 60.258351, as expected and thus  
    //the "C" locale was use for conversion  
}

I guess the conclusion so far is that STL objects in threads where _configthreadlocale(_ENABLE_PER_THREAD_LOCALE) is enabled is indeed using the C Runtime locale.

It is possible to work around this by setting both the Std lib locale and the C Runtime locale with the locale::global() call. But as Std lib locale is not thread safe and not affected by the _ENABLE_PER_THREAD_LOCALE, we can still run in to multithreading problems with this workaround.

0

精彩评论

暂无评论...
验证码 换一张
取 消