跨进程发送图像的最有效方法

时间:2010-03-29 07:20:47

标签: windows delphi image ipc marshalling

目标

将一个过程生成的图像高效且高速地传递到另一个过程。这两个进程在同一台计算机上运行,​​并在同一桌面上运行。操作系统可能是WinXP,Vista和Win7。

详细说明

第一个过程仅用于控制与产生图像的设备的通信。这些图像大小约为500x300px,每秒可更新数百次。第二个过程需要这些图像来处理它们。第一个过程使用第三方API将图像从设备绘制到HDC。这个HDC必须由我提供。

注意:两个进程之间已建立连接。它们通过匿名管道进行通信并共享内存映射文件视图。

思想

如何以尽可能少的工作实现这一目标?我的意思是既为计算机工作又为我工作(当然;))。我正在使用Delphi,所以也许有一些组件可用于这样做?我想我总是可以绘制到任何图像组件的HDC,将内容保存到内存流,通过内存映射文件复制内容,在另一侧解压缩并将其绘制到目标HDC。我还读到了一个可用于编组图像的IPicture界面。我需要尽可能快,所以开销越小越好。我不希望只是通过复制一些图像来强调机器。

你有什么想法?我很欣赏这一切!

5 个答案:

答案 0 :(得分:11)

使用Memory Mapped File

对于Delphi参考,请参阅Memory-mapped Files in DelphiShared Memory in Delphi

对于更通用的方法,您可以查看使用管道或通过TCP发送位图数据。如果需要,这将允许您更容易地在节点之间分发图像数据。

答案 1 :(得分:4)

使用共享内存传递图像数据,以及其他东西(命名管道,套接字......)来协调切换。

答案 2 :(得分:3)

在某些情况下,您可以跨进程传递HBITMAP句柄。我之前已经看过它了(是的,在XP / Vista上),当我的一位同事向我展示时,团队中的其他人都感到惊讶。

如果内存正确地为我服务,我相信如果HBITMAP被分配了一个GDI函数(CreateBitmap,CreateCompatibleBitmap,CreateDIBitmap等等),它将起作用。由LoadBitmap创建的HBIMAP句柄将不起作用,因为它只是一个指针到进程内资源。

那,我认为当你将HBITMAP分享到另一个进程时,除了正常的BitBlt操作之外,不要尝试对它做任何特殊的事情。

至少那是我记得的。我们很幸运,因为我们已经编写了图形库来管理所有图像,如HBITMAP。

YMMV

答案 3 :(得分:1)

好吧,好像内存映射文件和管道是正确的方法。这不是太糟糕,因为这两个进程已经共享一个MMF和两个管道(用于双向通信)。要解决的唯一问题是如何使用尽可能少的复制操作传递数据。

运行良好的设计如下(顺序流程):

过程1(想要图像)

  • 向进程2发送信号(通过管道1)以将映像存储在共享内存中
  • 进入睡眠状态并等待响应(阻止从管道2读取)

过程2(提供图像)

  • on signal(通过管道1)唤醒并告诉硬件设备绘制到HDC 1(这是由共享内存支持,见下文)
  • 向过程1发送信号(通过管道2)
  • 进入睡眠状态并等待新工作(通过管道1)

过程1(想要图像)

  • on signal(通过管道2)唤醒并从共享内存绘制到目标HDC 2

现在通过共享内存进行图像传输(我的目标是使用不超过一个额外的复制操作):

进程2通过HBITMAP创建CreateDIBSection,并提供文件映射的句柄和映射视图的偏移量。因此,图像数据存在于共享存储器中。这将创建一个HBITMAP,它被选入HDC 1(也由流程2创建),从现在开始将由流程2使用。

进程1使用StretchDIBits和指向映射视图内存的指针(如here所述)。这似乎是将内存中的位直接输入另一个HDC(在本例中为HDC 2)的唯一功能。其他函数会先将它们复制到某个中间缓冲区,然后再将它们从那里传输到最终的HDC。

所以最后看来需要转移的比特大约是开头的两倍。但我认为这是好的,除非在进程之间共享GDI句柄是可能的。

注意:我使用管道代替信号,因为我也需要传输一些额外的数据。

答案 4 :(得分:0)

我可以看到这一点,你有两个选择:

  1. 仅将图像句柄/指针传递给其他进程,因此这两个进程仅对一个图像集合起作用。
  2. 将图像内容复制到其他进程,然后处理副本。
  3. 哪种方法最好取决于您的设计。两种方法的最佳工具是“内存映射文件”或“命名管道”。这是你能得到的最快的。内存映射文件可能是进程间通信的最快形式,但却没有将“客户端 - 服务器”范例构建到其中。所以你必须自己同步MMF的访问。另一方面,命名管道几乎同样快,但客户端 - 服务器范例构建正确。速度的差异主要来自于此。

    现在由于更新的共享速度,第一种方法可能会更好,但是您必须注意进程之间的同步,因此它们不会同时读/写单个映像。此外,还可以使用某种缓存或其他智能技术,因此您可以将流量降至最低。当面对如此高水平的通信时,总是建议在可能的情况下寻找降低该水平的方法。

    对于基于命名管道的IPC的快速实现,您可以使用我的IPC实现。它是面向消息的,因此您不必担心管道技术细节。它还在幕后使用线程池,并且具有最小的额外开销。 您可以对其进行压力测试并亲自查看(对于完整的客户端 - 服务器请求 - 响应周期,典型消息需要0.1 ms。)