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

