首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Synchronize()挂起线程

Synchronize()挂起线程
EN

Stack Overflow用户
提问于 2010-09-23 01:56:05
回答 3查看 3.5K关注 0票数 6

我正在用Delphi编写一个dll库,其中包含由它创建的多个线程。让我一步一步地描述这个问题。我很抱歉事先做了冗长的描述:-(.

让我们暂时忘掉这个库。我创建了一个windows应用程序,它将显示多个摄像头的视图。我创建了一个窗口,用于显示来自单个摄像头的视图,其中包含一个TImage控件。有一个线程(同步子)每隔几毫秒从相机下载一次当前图像,并将其分配给该窗口的TImage控件(使用TThread ()方法)。应用程序在启动时创建该窗口的多个实例(每个实例都有一个单独的线程),因此您可以同时从多个摄像头看到实时视图。更重要的是,所有这些查看窗口都是主应用程序窗口的父窗口,所以它们会出现在主应用程序窗口中。

在我决定将这两个窗口放入dll库之前,一切都运行得很好。我只是出于某些原因发现它是必要的,但现在它们并不重要。因此,我创建了一个新的dll库,将现有的主窗口和相机视图窗口添加到项目中,并导出了一个创建并返回主窗口实例的函数。创建主窗口时,它会创建几个摄影机视图窗口,使其成为它们的父窗口。

然后,出于测试目的,我创建了一个应用程序,它从库中导入上述dll函数,并在启动时调用它来获取主窗口的实例;然后在屏幕上显示它(以非模式状态)。

当我启动这个应用程序时,我发现当时我无法从任何相机中获得一张图像。当我调试它时,我注意到当线程调用Synchronize()方法时,它永远挂起。在将这两个窗口都放入dll之前,这不会发生。

这就是我的问题。老实说,这是我第一次使用库,到目前为止,我已经解决了许多其他问题。你可能想知道为什么我使用窗口而不是框架...因此,每当我在dll中创建TFrame的实例时,我都会得到一个异常,说“控件xxx没有父窗口”。我不知道该怎么做,所以我改用了windows :-(.

你能告诉我如何处理同步问题吗?当应用程序启动时,主线程似乎没有以任何方式被阻塞,因为它接受点击按钮等。那么问题是什么呢?

求求你救命!

提前谢谢你!!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 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对象,而这个对象将无法工作。

票数 13
EN

Stack Overflow用户

发布于 2010-09-23 02:26:35

使用Synchronize不是一个好主意,因为它往往会导致像这样的竞争情况。我不知道您的代码中具体发生了什么--如果看不到任何代码就很难判断--但实际上这种类型的问题非常常见。

线程间的通信最好使用队列来完成。如果你有最新的版本,Delphi,在Generics.Collections中有一个TThreadedQueue<T>类非常适合做这类事情。将0传递给构造函数中的PopTimeout参数,让相机线程推送图像,并让主线程使用第三个PopItem重载轮询队列,如下所示:

代码语言:javascript
运行
复制
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 )中找到一个。

票数 3
EN

Stack Overflow用户

发布于 2016-01-22 22:40:51

我发现了两种解决Synchronize()挂起线程的方法(在Delphi7中):

  1. 在Dll窗体上放置一个TTimer并调用onTimer事件调用Dll

procedure TPluginForm.Timer1Timer(Sender: TObject); begin CheckSynchronize; end;

  1. Add this module to uses section of the Dll form
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3772196

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档