主线“被放弃的关键部分被阻止”

时间:2011-01-07 05:43:39

标签: multithreading delphi delphi-2010

我使用OmniThreadLibrary获得了多线程应用。我错误地使用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。将线程逗留时间设置为60s而不是10s至少可以让我这样做。

2 个答案:

答案 0 :(得分:2)

首先,我不明白你为什么要在后台线程中调用ADO存储过程“滥用” - 它应该完美无缺,除非你在不同的线程中有一些混乱'公寓或其他消息(例如监控线程通知)。

我不知道究竟是什么导致了您的问题,但我将分享Delphi ADO多线程领域的一些经验。 COM / OLE STA消息传递是这里的主要嫌疑人。

后台线程应该更好地作为MTA。我不知道Delphi 2010是否自己这样做,但Delphi 2006没有 - 确保查看CoInitializeEx调用的来源 - 如果没有调用COINIT_MULTITHREADED=$00标志,该线程被认为是公寓中立的,并通过STA /主线程进行编组。每个其他的init方法都会为你提供一个很好的STA线程。

你应该:

  • 为您的背景线程提供适当的COM ini / finalization作为MTA
  • 仅使用创建它们的公寓中的所有ADO组件
  • 不创建其他STA线程(主线程默认为1);结合使用其他锁定的消息传递是PITA
  • 过多的问题
  • 永远不要将ADO异步功能与多线程一起使用

答案 1 :(得分:1)

我建议您使用CodeSite等日志库来追踪主线程停止的位置。