我正在用Delphi编写一个dll库,其中包含由它创建的多个线程。让我一步一步地描述这个问题。我很抱歉事先做了冗长的描述:-(.
让我们暂时忘掉这个库。我创建了一个windows应用程序,它将显示多个摄像头的视图。我创建了一个窗口,用于显示来自单个摄像头的视图,其中包含一个TImage控件。有一个线程(同步子)每隔几毫秒从相机下载一次当前图像,并将其分配给该窗口的TImage控件(使用TThread ()方法)。应用程序在启动时创建该窗口的多个实例(每个实例都有一个单独的线程),因此您可以同时从多个摄像头看到实时视图。更重要的是,所有这些查看窗口都是主应用程序窗口的父窗口,所以它们会出现在主应用程序窗口中。
在我决定将这两个窗口放入dll库之前,一切都运行得很好。我只是出于某些原因发现它是必要的,但现在它们并不重要。因此,我创建了一个新的dll库,将现有的主窗口和相机视图窗口添加到项目中,并导出了一个创建并返回主窗口实例的函数。创建主窗口时,它会创建几个摄影机视图窗口,使其成为它们的父窗口。
然后,出于测试目的,我创建了一个应用程序,它从库中导入上述dll函数,并在启动时调用它来获取主窗口的实例;然后在屏幕上显示它(以非模式状态)。
当我启动这个应用程序时,我发现当时我无法从任何相机中获得一张图像。当我调试它时,我注意到当线程调用Synchronize()方法时,它永远挂起。在将这两个窗口都放入dll之前,这不会发生。
这就是我的问题。老实说,这是我第一次使用库,到目前为止,我已经解决了许多其他问题。你可能想知道为什么我使用窗口而不是框架...因此,每当我在dll中创建TFrame的实例时,我都会得到一个异常,说“控件xxx没有父窗口”。我不知道该怎么做,所以我改用了windows :-(.
你能告诉我如何处理同步问题吗?当应用程序启动时,主线程似乎没有以任何方式被阻塞,因为它接受点击按钮等。那么问题是什么呢?
求求你救命!
提前谢谢你!!
发布于 2010-09-23 02:22:19
当您调用TThread.Synchronize
时,线程和方法指针被添加到Classes.pas中的全局SyncList: TList
。在主可执行文件的TApplication.Idle
例程中,调用CheckSynchronize
来检查SyncList
,但它将检查可执行文件中的版本,而不是DLL中的版本。最终结果是,您的同步方法永远不会被调用。
最简单的修复方法是从DLL切换到包,这将消除重复的SyncList
。
另一种方法是覆盖exe的Application.OnIdle
回调,并手动调用DLL的CheckSynchronize
。不过,您需要从应用程序获得一些帮助,因为您的DLL也将有一个Application
对象,而这个对象将无法工作。
发布于 2010-09-23 02:26:35
使用Synchronize不是一个好主意,因为它往往会导致像这样的竞争情况。我不知道您的代码中具体发生了什么--如果看不到任何代码就很难判断--但实际上这种类型的问题非常常见。
线程间的通信最好使用队列来完成。如果你有最新的版本,Delphi,在Generics.Collections
中有一个TThreadedQueue<T>
类非常适合做这类事情。将0传递给构造函数中的PopTimeout参数,让相机线程推送图像,并让主线程使用第三个PopItem重载轮询队列,如下所示:
var
CurrentItem: TImage;
begin
if ThreadQueue.PopItem(CurrentItem) = wrSignaled then
UpdateImage(CurrentItem); //or however you do it
end;
(如果队列中没有任何内容,PopItem将返回wrTimeout。)
如果您没有安装Delphi,您将需要构建自己的线程安全队列,或者从第三方源(如Primoz Gabrielcic's OmniThreadLibrary )中找到一个。
发布于 2016-01-22 22:40:51
我发现了两种解决Synchronize()
挂起线程的方法(在Delphi7中):
TTimer
并调用onTimer
事件调用Dllprocedure TPluginForm.Timer1Timer(Sender: TObject); begin CheckSynchronize; end;
https://stackoverflow.com/questions/3772196
复制相似问题