这是一个很长的问题,但我们开始了。有一个版本的FormatDateTime据说是线程安全的,因为您使用
GetLocaleFormatSettings(3081, FormatSettings); 得到一个值,然后你可以这样使用它;
FormatDateTime('yyyy', 0, FormatSettings); 现在设想两个定时器,一个使用TTimer (间隔为1000 so ),然后另一个定时器创建为这样(10 so间隔);
CreateTimerQueueTimer
(
FQueueTimer,
0,
TimerCallback,
nil,
10,
10,
WT_EXECUTEINTIMERTHREAD
);现在的位,如果在回调和计时器事件,你有以下的代码;
for i := 1 to 10000 do
begin
FormatDateTime('yyyy', 0, FormatSettings);
end;注:没有作业。这几乎立即导致访问违规,有时是20分钟后,随便什么地方。现在,如果用C++Builder编写这段代码,它就不会崩溃。我们正在使用的标题转换是绝地JwaXXXX的转换。即使我们围绕代码在Delphi版本中设置锁,它也只会延迟不可避免的发生。我们已经查看了原始的C头文件,它们看起来都很好,C++使用Delphi有什么不同的方式吗?线程安全版本的FormatDatTime看起来是重新进入。任何可能曾见过这种想法或想法的人。
更新:
为了缩小这一点,FormatSettings作为一个const传入,那么如果他们使用相同的副本(结果是在函数调用中传递一个本地版本会导致同样的问题),这有什么关系吗?另外,接受FormatDateTime的FormatSettings版本不调用GetThreadLocale,因为它已经在FormatSettings结构中包含了区域设置信息(我通过遍历代码进行了双重检查)。
我提到没有分配来明确表示没有共享存储被访问,所以不需要锁定。
WT_EXECUTEINTIMERTHREAD是用来简化问题的。我的印象是,你应该只在很短的任务中使用它,因为它可能意味着如果它运行很长时间,它就会错过下一个间隔?
如果您使用的是普通的旧TThread,那么问题就不会发生。我在这里要了解的是,使用TThread或TTimer是可行的,但是使用在VCL之外创建的线程不起作用,这就是为什么我问C++生成器使用VCL/Delphi的方式是否有区别。
首先,前面提到的这段代码也会失败(但花费的时间更长),一段时间后,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窗口内的同一个位置,有时是访问冲突,有时可能是无效的指针操作。我正在使用德尔福2009顺便。
更新2:
Roddy (下面)指出了Ontimer事件(不幸的是,Winsock,也就是TClientSocket)使用了windows消息泵(顺便说一下,如果使用IOCP和重叠IO拥有一些好的Winsock2组件将是很好的),因此就可以摆脱它了。但是,有谁知道如何在CreateQueueTimerQueue上设置什么样的线程本地存储呢?
谢谢你花时间思考和回答这个问题。
发布于 2008-12-10 01:34:34
我不确定用“答案”回答我自己的问题是否好,但这似乎合乎逻辑,请告诉我这是否不酷。
我想我已经发现了问题,线程本地存储的想法让我跟随了一堆线索,我发现了这条神奇的线条;
IsMultiThread := True;
从帮助;
"IsMultiThread设置为true,表示内存管理器应该支持多个线程。IsMultiThread被BeginThread和类工厂设置为true。“
当然,这是而不是通过使用TTimer的单个主VCL线程设置的,但是在使用TThread时是为您设置的。如果我手动设置它,问题就会消失。
在C++Builder中,我不使用TThread,但使用以下代码显示;
if (IsMultiThread) {
ShowMessage("IsMultiThread is True!");
}这是自动为你设定的。
我真的很高兴人们的意见,以便我可以找到这一点,我希望它可以帮助别人。
发布于 2008-12-09 15:41:02
由于DateTimeToString ( FormatDateTime调用的)使用GetThreadLocale,您可能希望为每个线程设置一个本地FormatSettings变量,甚至可以在循环之前在局部变量中设置FormatSettings。
它也可能是导致这种情况的WT_EXECUTEINTIMERTHREAD参数。请注意,它声明它只应用于非常短的任务。
如果问题仍然存在,问题可能实际上是在其他地方,这是我第一次看到这个问题,但我没有足够的信息来确定代码所做的事情。
有关访问冲突发生位置的详细信息可能会有所帮助。
发布于 2008-12-09 16:10:10
您确定这实际上与FormatDateTime有关吗?你提到没有作业说明,这是你问题的一个重要方面吗?如果您调用其他字符串返回函数,会发生什么情况?(确保它不是一个常量字符串。)编写自己的函数,在返回之前调用UniqueString(Result)。)
FormatSettings变量线程是特定的吗?这就是为FormatDateTime设置额外参数的意义,因此每个线程都有自己的私有副本,保证在函数活动时不会被任何其他线程修改。
计时器队列对此问题是否重要?或者,当您使用一个普通的旧TThread并在Execute方法中运行您的循环时,会得到相同的结果吗?
你的确警告说,这是一个很长的问题,但似乎你可以做一些事情来缩小它的规模,缩小问题的范围。
https://stackoverflow.com/questions/352543
复制相似问题