Wu Adam wrote:
> The "Exception" class in SysUtils unit has a serie of constructors 
> Create*Fmt*() that combines "Format" functionality into the constructor. 
> When I examine its source I found out those constructors all use the 
> "Format(Format, Args)" routine. However, the Delphi documentation 
> clearly stated that the "Format(Format, Args)" routine is NOT 
> threadsafe. So, I think it also implies that the Exception class 
> constructors that use them are NOT threadsafe, which means, raising an 
> exception using the Create*Fmt* constructor is NOT threadsafe!(?!)
> 
> After discovering this problem, I coded my own "threadsafe" version 
> exception class which uses the threadsafe "Format(Format, Args, 
> FmtSettings)" routine, feeding it a per-thread copy of FormatSettings.
> 
> Yes, you can call me paranoid, because even I have the same feeling. So 
> I really want to know whether my suspect is true or I am practising 
> something that is not necessary...

The non-thread-safe part of Format is where it accesses the various 
global locale settings. The thread-safe version take a TFormatSettings 
record that provides a local copy of all the relevant settings, so it no 
longer needs to access the shared global values. If, when you create an 
exception object, your format string doesn't require access to any of 
those global variables, then it is safe to create that object.

Safe format strings include s, d, u, x, and p, as long as the data value 
is not a Variant. If the data value is a Variant, then there may be a 
call to FloatToStr via FormatVarToStr and Variants._VarToLStr.

The e, f, g, m, and n format strings trigger access to the 
DecimalSeparator, ThousandSeparator, CurrencyString, CurrencyFormat, and 
NegCurFormat variables. In addition, the m format string requires 
accessing the CurrencyDecimals variable.

Furthermore, accessing those variables is only unsafe if their values 
can ever change while a call to Format is active. In the VCL source 
code, they only change due to calls to GetLocaleFormatSettings and 
GetFormatSettings. Delphi never calls the former, and it only calls the 
latter in two places. The first is in the initialization section of 
SysUtils.pas, which is required for initializing the variables when your 
program starts up. The other place is in TApplication.CheckIniChange, 
and the function is only called if Application.UpdateFormatSettings is 
True. It's True by default, but you can set it to False. CheckIniChange 
gets called in response to your main window receiving a wm_WinIniChange 
or TaskbarCreated message.

-- 
Rob
_______________________________________________
Delphi mailing list -> [email protected]
http://www.elists.org/mailman/listinfo/delphi

Reply via email to