gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 15:24:32 25 4
gpt4 key购买 nike

这个问题有点长,但我们开始吧。有一个 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 中编写该代码,它永远不会崩溃。我们使用的 header 转换是 JEDI JwaXXXX 的 header 转换。即使我们在 Delphi 版本中对代码加锁,也只会延迟不可避免的事情。我们已经查看了原始的 C 头文件,看起来一切都不错,C++ 使用 Delphi 运行时是否有一些不同的方式? FormatDatTime 的线程安全版本看起来是可重入的。来自以前可能见过此内容的任何人的任何想法或想法。

更新:

为了缩小范围,FormatSettings 作为常量传入,因此它们是否使用相同的副本是否重要(因为事实证明在函数调用中传递本地版本会产生相同的问题)?此外,采用 FormatSettings 的 FormatDateTime 版本不会调用 GetThreadLocale,因为它已经在 FormatSettings 结构中具有区域设置信息(我通过单步执行代码进行了双重检查)。

我提到没有分配是为了明确表示没有共享存储被访问,因此不需要锁定。

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。

更新2:

Roddy(下)指出 Ontimer 事件(不幸的是 Winsock,即 TClientSocket)使用 Windows 消息泵(顺便说一句,如果有一些使用 IOCP 和 Overlapping IO 的不错的 Winsock2 组件会很好),因此推送远离它。但是,有谁知道如何查看 CreateQueueTimerQueue 上设置了哪种线程本地存储?

感谢您花时间思考并回答这个问题。

最佳答案

我不确定对我自己的问题发布“答案”是否是一种好的形式,但这似乎合乎逻辑,如果这不酷,请告诉我。

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

IsMultiThread := True;

来自帮助;

“IsMultiThread 设置为 true 表示内存管理器应支持多线程。BeginThread 和类工厂将 IsMultiThread 设置为 true。”

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

在 C++Builder 中,我不使用 TThread,但它通过使用以下代码出现;

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

这是自动为您设置的。

我真的很高兴人们的意见,这样我就能找到这个,我希望它能对其他人有所帮助。

关于multithreading - Delphi Win API CreateTimerQueueTimer 线程和线程安全 FormatDateTime 崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/352543/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com