Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread-Safeness of FloatToStr / DateToStr

I just found in the documentation that FloatToStr and DateToStr are not thread-safe in their one-paramater overloads. The reason is that they access localization information stored in global variables.

My question is: is this of any practical relevance if I do not change the format settings at runtime? As far as I understand it, I'm on the safe side as long as everyone only reads the format settings - even from multiple threads.

Is that true or am I missing something here?

Thanks.

like image 927
jpfollenius Avatar asked May 19 '11 07:05

jpfollenius


People also ask

Are global variable thread-safe?

Local variables and parameters are always thread-safe. Instance variables, class variables, and global variables may not be thread-safe (but they might be). Nevertheless, threads and shared variables can be useful.

What is meant by thread safety in Java?

What is thread safety ? thread-safety or thread-safe code in Java refers to code that can safely be utilized or shared in concurrent or multi-threading environment and they will behave as expected.

Is final variable thread-safe?

Final variables are immutable references, so a variable declared final is safe to access from multiple threads. You can only read the variable, not write it.


2 Answers

FloatToStr, DateToStr and others similar functions are reading global format settings. So, if your application does not change these settings for these function calls, then it is thread safe. The following code on opposite is not thread safe:

DecimalSeparator := ',';
try
  s := FloatToStr(123.45);
finally
  DecimalSeparator := '.';
end;

When you need the tread safety and "local" format settings, then you have to use overloaded functions, which take as last parameter: AFormatSettings: TFormatSettings. So, to make above code thread safe you have to write:

var
  fs: TFormatSettings;

GetLocaleFormatSettings(GetThreadLocale, fs);
fs.DecimalSeparator := ',';
s := FloatToStr(123.45, fs);

Notes:

  1. GetLocaleFormatSettings and fs initialization may be called once and then fs may be used multiple times. This will speedup the code.
  2. Instead of GetLocaleFormatSettings may be used TFormatSettings.Create. I am not sure when that was introduced, but I see that in Delphi XE.
like image 165
robmil Avatar answered Oct 27 '22 05:10

robmil


Even the global settings can change when Application.UpdateFormatSettings (Delphi 7, don't know about Delphi XE) is True. When a user changes the Regional and Language options of Windows, this will be reflected in your application. You can circumvent this by setting UpdateFormatSettings to False, but even then you can't be sure, maybe there is some third party library you use that changes it.

I had some problems with our own application: Nowhere in our application the global formatsettings were changed, but still there was information loss because a float was converted to a string and when the string was converted back to float, the formatsettings were magically changed. (So you had this: 1.2 -> convert to string -> '1.2' -> black magic that changed formatsettings.decimalseparator -> convert to float -> 12).

My suggestion: only use the not thread-safe version for UI purposes so the user sees dates and floats the way he likes them to see, for everything else, use the thread-safe version. Conversions inside your application will then be consistent and don't give surprises.

like image 31
The_Fox Avatar answered Oct 27 '22 05:10

The_Fox