当前位置:  开发笔记 > 开发工具 > 正文

Delphi Win API CreateTimerQueueTimer线程和线程安全的FormatDateTime崩溃

如何解决《DelphiWinAPICreateTimerQueueTimer线程和线程安全的FormatDateTime崩溃》经验,为你挑选了1个好方法。

这是一个很长的问题,但我们走了.有一个版本的FormatDateTime,据说是您使用的线程安全

GetLocaleFormatSettings(3081, FormatSettings); 

得到一个值然后你可以像这样使用它;

FormatDateTime('yyyy', 0, FormatSettings); 

现在想象两个计时器,一个使用TTimer(间隔说1000毫秒),然后另一个计时器创建如此(10毫秒间隔);

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的线程安全版本看起来是可重入的.任何可能以前看过这个的人的想法或想法.

更新:

为了缩小这一点,FormatSettings作为const传入,所以如果它们使用相同的副本(因为事实证明在函数调用中传递本地版本会产生同样的问题)是否重要?采用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;

这会导致相同类型的故障,正如我之前所说,故障永远不会出现在CPU窗口内的同一位置等.有时它是一种访问冲突,有时它可能是一个无效的指针操作.我正在使用Delphi 2009 btw.

更新2:

Roddy(下面)指出了Ontimer事件(不幸的是还有Winsock,即TClientSocket)使用windows消息泵(除了使用IOCP和Overlapping IO有一些不错的Winsock2组件会很好),因此推动离开从中.但是,是否有人知道如何在CreateQueueTimerQueue上设置哪种线程本地存储?

感谢您抽出宝贵时间思考并回答这个问题.



1> Bruce..:

我不确定在我自己的问题上发表"答案"是否是好的形式,但它似乎合乎逻辑,让我知道这是不是很酷.

我想我已经找到了问题,线程本地存储的想法引导我跟随一堆线索,我发现了这条神奇的线条;

IsMultiThread:= True;

从帮助;

"IsMultiThread设置为true表示内存管理器应该支持多个线程.IllMultiThread由BeginThread和类工厂设置为true."

这当然不是通过使用TTimer使用单个主VCL线程来设置的,但是在使用TThread时会为您设置.如果我手动设置它,问题就会消失.

在C++ Builder中,我不使用TThread,但它使用以下代码显示;

if (IsMultiThread) {
  ShowMessage("IsMultiThread is True!");
}

就是它会自动为你设置.

我真的很高兴人民的意见,以便我能找到这一点,我希望它可以帮助其他人.

推荐阅读
虎仔球妈_459
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有