Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading “主线程”;在被废弃的关键截面上堵塞”;_Multithreading_Delphi_Delphi 2010 - Fatal编程技术网

Multithreading “主线程”;在被废弃的关键截面上堵塞”;

Multithreading “主线程”;在被废弃的关键截面上堵塞”;,multithreading,delphi,delphi-2010,Multithreading,Delphi,Delphi 2010,我有一个多线程应用程序使用。我错误地使用OTL在辅助线程中打开ADO存储过程,除非出现错误(大多数情况下甚至出现错误),否则这些存储过程都可以工作。不幸的是,在这种特殊情况下有一个问题 当我打开一个特定的表单时,我在一个线程“必须至少有一个字段”中得到一个异常,该线程将数据集复制到一个kb内存表中,我处理该表并向一个监控线程发送消息。该消息到达并成功存储在数据库中。当我关闭该窗体时,主VCL线程挂起 kbMemTable.LoadFromDataset(StoredProc, []); // t

我有一个多线程应用程序使用。我错误地使用OTL在辅助线程中打开ADO存储过程,除非出现错误(大多数情况下甚至出现错误),否则这些存储过程都可以工作。不幸的是,在这种特殊情况下有一个问题

当我打开一个特定的表单时,我在一个线程“必须至少有一个字段”中得到一个异常,该线程将数据集复制到一个kb内存表中,我处理该表并向一个监控线程发送消息。该消息到达并成功存储在数据库中。当我关闭该窗体时,主VCL线程挂起

kbMemTable.LoadFromDataset(StoredProc, []); // throws
在调试器中暂停应用程序并查看线程列表,主VCL线程显示:

"Blocked on critical section which is abandoned owned by Process 0"
OTL线程仍然处于活动状态,并且时间不在线程池中,因此除了主线程之外,似乎所有的东西都在工作。我还使用了DevExpress和Raise组件,它们有自己的线程,但没有命名它们(而且似乎不是问题的一部分),这意味着我有12个线程,其中只有5个可以识别

我强烈怀疑Delphi数据库中有什么东西抓住了关键部分,然后由于异常而未能发布它。在我直接使用的Delphi/数据库源代码单元中似乎没有任何关键部分,但显然在某个地方有一个关键部分

这涉及太多的源代码,我的测试应用程序不会显示这种行为

我想了解有关追踪此信息的任何提示。

我目前的想法是切换到调试dcu,并对我能找到的每个关键部分创建进行断点,然后看看会发生什么。我可以解决引发第一个异常的问题,但我担心其他一些异常可能会在需要处理的领域产生同样的影响。所以我想先解决这个问题


编辑:关键部分由调用TADOStroredProc.ExecProc的线程拥有。该线程在处理异常后正常完成,因此,除非我快速跳入调试器,否则线程在我看到它之前就会从池中老化,因此上面的ProcessID=0。将线程的延迟时间设置为60秒而不是10秒至少给了我这个机会。

我建议您使用诸如CodeSite之类的日志库来跟踪主线程停止的位置。

首先,我不明白为什么您将在后台线程中打开ADO存储的进程称为“误用”-它应该可以完美地工作,除非不同线程的单元或其他消息(例如监视线程通知)中有一些混乱。

我不知道到底是什么原因导致了您的问题,但我将分享一些关于Delphi ADO多线程领域的经验。COM/OLE STA消息是这里的主要嫌疑犯

后台线程应该更像MTA。我不知道Delphi 2010是否自己做到了这一点,但Delphi 2006没有做到这一点——为了确保这一点,请查看对
CoInitializeEx
的调用的源代码——如果不使用
Conit\u MULTITHREADED=$00
标志调用,则该线程被认为是单元中立的,并通过STA/主线程封送。其他每一个init方法都会为您提供一个不错的STA线程。

你应该:

  • 以MTA的形式为您的反向线程提供适当的COM ini-/终结
  • 仅使用创建ADO组件的单元中的所有ADO组件
  • 不创建其他STA线程(主线程默认为一个);将消息传递与其他锁定相结合是一种太多的PITA
  • 切勿将ADO异步功能与多线程一起使用

我看不出CodeSite在这方面有什么帮助。我有自己的日志记录程序,它也有同样的问题——除非我对Delphi库代码进行大量修改(通过在所有地方添加日志记录调用),否则我的日志记录程序根本不会告诉我任何事情。您能解释一下CodeSite有什么帮助吗?因为SP是在中创建的,并且正在使用属于主VCL线程的DBSession。所以我跨越了公寓的界限,到目前为止,这是可行的。隐藏的步骤是在SP打开后在主线程中设置“TDatasource.Enabled:=true”,因此触发所有VCL重绘事件。但它看起来确实违反了规则,所以我有点谨慎。谢谢你的提示,这就是我想要的。是的,ADO异步+线程是一场噩梦。从自由线程切换到MTA不会改变这种行为。我现在怀疑,实际上是DB代码中的异常处理造成了问题——特定的异常绕过了关键部分版本。因此,任何导致创建临界段的多线程Conit模式都将失败。这让人放心,因为它可能是这个特定的异常,而不是习惯性的“如果发生异常,则泄漏关键部分”模式。我有过其他例外情况,但没有这个