主线程“在被放弃的关键部分上被阻塞”
我有一个使用 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 。将线程停留时间设置为 60 秒而不是 10 秒至少可以让我做到这一点。
I've got a multithreaded app using the OmniThreadLibrary. I am misusing the OTL to open ADO stored procedures in secondary threads which works unless there's an error (and mostly even then). Unfortunately in this particular case there's a problem.
When I open a particular form I get an exception in a thread "There must be at least one field" copying a dataset into a kb memory table, which I handle and send a message to a monitoring thread. That message arrives and is stored successfully in the database. When I close that form the main VCL thread hangs.
kbMemTable.LoadFromDataset(StoredProc, []); // throws
Pausing the app in the debugger and looking at the thread list the main VCL thread shows:
"Blocked on critical section which is abandoned owned by Process 0"
The OTL threads are still live and time out of the thread pool, so it seems that everything is working except the main thread. I'm also using DevExpress and Raise components which have their own threads but don't name them (and don't seem to be part of the problem) which means I have 12 threads of which only 5 are identifiable.
I strongly suspect that something in the Delphi database has grabbed that critical section then failed to release it due to the exception. There don't seem to be any critical sections in the Delphi/database source code units that I'm using directly, but obviously there's one there somewhere.
This involves way too much source code to include, and my test app doesn't display the behaviour.
I'm asking for any tips on tracking this down.
My current thought is to switch to debug dcu's and breakpoint every critical section creation I can find, then see what happens. I could address the problem that's throwing the first exception, but I'm concerned that some other exception could have the same effect out in the field where it would be a pain to deal with. So I'd like to fix this problem first.
Edit: the critical section is owned by the thread that calls TADOStroredProc.ExecProc. That thread completes normally after handling the exception, so unless I leap into the debugger quickly the thread ages out of the pool before I see it, hence the ProcessID=0 above. Setting the thread linger time to 60s instead of 10s at least gives me that.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先,我不明白为什么您将在后台线程中打开 ADO 存储过程称为“误用” - 它应该完美地工作,除非您在不同线程的公寓中出现一些混乱或其他消息传递(例如监视线程通知)。
我不知道到底是什么原因导致了您的问题,但我将分享一些关于 Delphi ADO 多线程领域的经验。 COM/OLE STA 消息传递是这里的主要嫌疑点。
后台线程确实应该像 MTA 那样更好。我不知道 Delphi 2010 本身是否会执行此操作,但 Delphi 2006 不会 - 为了确保这一点,请在源代码中查找对
CoInitializeEx
的调用 - 如果没有使用COINIT_MULTITHREADED 调用=$00
标志,该线程被认为是单元中立的,并通过 STA/主线程进行编组。每个其他 init 方法都会为您提供一个不错的 STA 线程。您应该:
First, I don't see why you're calling opening an ADO stored proc in a background thread a "misuse" - it should work flawlessly, unless you have some mess in the different threads' apartments or other messaging (eg the monitoring thread notifications).
I don't know what exactly causes your problem, but I will share some experiences on the Delphi ADO multithreading field. The COM/OLE STA messaging is the main suspect here.
Background threads should really better be as MTA. I don't know if Delphi 2010 does this by itself, but Delphi 2006 doesn't - to make sure, look in the sources for calls to
CoInitializeEx
- if not called w/ theCOINIT_MULTITHREADED=$00
flag, the thread is considered apartment-neutral and marshals through the STA/main thread. Every other init method will get you a nice STA thread.You should:
我建议您使用 CodeSite 等日志库来跟踪主线程停止的位置。
I suggest you to use a logging library such as CodeSite to track down where the main thread is stopped.