这是一个很长的问题,但我们走了。还有一个是被说成是线程安全的,这与使用Delphi Win API CreateTimerQueueTimer线程和线程安全FormatDateTime崩溃
GetLocaleFormatSettings(3081, FormatSettings);
得到一个值,然后你可以使用它像这样的FormatDateTime的版本;
FormatDateTime('yyyy', 0, FormatSettings);
现在想象两个定时器,使用TTimer酮(间隔说1000毫秒),然后,像这样(10ms的时间间隔)中创建另一定时器;
CreateTimerQueueTimer
(
FQueueTimer,
0,
TimerCallback,
nil,
10,
10,
WT_EXECUTEINTIMERTHREAD
);
现在,如果在回调和定时器事件中您有下面的代码,
for i := 1 to 10000 do
begin
FormatDateTime('yyyy', 0, FormatSettings);
end;
注意没有赋值。这种情况在20分钟后几乎立即产生访问违规,无论在随机的地方。现在,如果你在C++ Builder中编写代码,它永远不会崩溃。我们正在使用的标题转换是JEDI JwaXXXX。即使我们在代码中使用Delphi版本的锁,它也只会拖延不可避免的。我们已经查看了原始的C头文件,它看起来很不错,C++使用Delphi运行时有一些不同的方式吗? FormatDatTime的线程安全版本看起来是可重入的。来自任何可能曾经见过此事的人的任何想法或想法。
UPDATE:
要缩小下来一点,FormatSettings传递作为一个常量,所以它的问题,如果他们使用相同的副本(因为它原来传递函数调用中的本地版本yeilds同样的问题)?此外,使用FormatSettings的FormatDateTime版本不会调用GetThreadLocale,因为它已经在FormatSettings结构中具有Locale信息(我通过逐步检查代码进行了双重检查)。
我提到了没有分配来说明没有共享存储被访问,所以不需要锁定。
WT_EXECUTEINTIMERTHREAD用于简化问题。我只是觉得你应该把它用于很短的任务,因为它可能意味着如果它运行了很长时间,它会错过下一个时间间隔?
如果您使用普通的老式TThread,则不会发生该问题。我在这里想到的是,使用TThread或TTimer工作,但使用在VCL之外创建的线程不会,因此我问C++ Builder使用VCL/Delphi RTL的方式是否有所不同。如上所述,此代码也失败(但需要更长时间),过了一段时间,CS:= TCriticalSection.Create;
CS.Acquire;
for i := 1 to LoopCount do
begin
FormatDateTime('yyyy', 0, FormatSettings);
end;
CS.Release;
而现在,我真的不明白,我写这个建议;
function ReturnAString: string;
begin
Result := 'Test';
UniqueString(Result);
end;
然后里面的每种类型的定时器的代码是;
for i := 1 to 10000 do
begin
ReturnAString;
end;
这将导致同种failiures的,正如我之前所说的故障是从未在CPU窗口等内同一个地方有时候这是一个访问冲突,有时它可能是一个无效的指针操作。我使用Delphi 2009 btw。
更新2:
罗迪(下)指出了OnTimer事件(不幸的是还Winsock的,即Tclientsocket构件实现)使用Windows消息泵(顺便说一句这将是很好,有一些很好的Winsock2组件使用IOCP和重叠IO),因此推动摆脱它。然而,有谁知道如何查看CreateQueueTimerQueue上设置的线程本地存储的种类?
感谢您花时间思考和解答此问题。
如果你创建一个标准的Delphi线程,那么就没有必要设置这个值。但有时候,就像在一个称为多线程的DLL中一样,你必须自己设置它。好点。 – mj2008 2009-01-13 09:09:55
帮助我,欢呼! – Blorgbeard 2009-11-30 02:24:35