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

目标

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

详细说明

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

注意:两个进程之间已经build立了连接。 他们通过匿名pipe道进行通信,并共享内存映射的文件视图。

思考

我怎样才能实现这个目标尽可能less的工作? 我的意思是既为电脑和我(当然)工作)。 我正在使用Delphi,所以也许有一些组件可以做到这一点? 我认为我总是可以绘制到任何图像组件的HDC,将内容保存到内存stream中,通过内存映射文件复制内容,在另一侧解压缩内容并将其绘制到目标HDC。 我也读了一个可以用来封送图片的IPicture接口。 我尽可能快地需要它,所以越less越好。 我不希望只通过复制一些图像来强调机器。

你有什么想法? 我感谢每一个想法!

Solutions Collecting From Web of "跨进程发送图像的最有效方式"

使用内存映射文件 。

对于Delphi引用,请参阅Delphi中的内存映射文件和Delphi中的 共享内存 。

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

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

在某些情况下,您可以跨进程传递HBITMAP句柄。 我之前就看到过这样做(是的,在XP / Vista上),当我的一位同事向我展示时,队员们都感到惊讶。

如果内存服务正确,我相信这将工作,如果HBITMAP分配与GDI函数之一(CreateBitmap,CreateCompatibleBitmap,CreateDIBitmap等…)由LoadBitmap创建的HBIMAP句柄将无法正常工作,因为它只是一个指针-proc资源。

我认为,当你将HBITMAP分享到其他进程时,除了正常的BitBlt操作以外,不要试图做任何特殊的事情。

至少这就是我所记得的。 我们很幸运,因为我们的图形库已经被编写来管理所有的图像作为HBITMAPs。

因人而异

好吧,似乎内存映射文件和管道是正确的路要走。 这不算太坏,因为这两个进程已经共享一个MMF和两个管道(用于双向通信)。 剩下的唯一要解决的问题是如何通过尽可能少的复制操作来传递数据。

工作得很好的设计看起来如下(顺序流程):

过程1(想要图像)

  • 给进程2发送信号(通过管道1)将图像存储在共享内存中
  • 去睡觉并等待响应(阻塞从管道2读取)

过程2(提供图像)

  • (通过管道1)唤醒,并告诉硬件设备绘制到HDC 1(这是由共享内存支持,见下文)
  • 给进程1(通过管道2)
  • 去睡觉,等待新的工作(通过管道1)

过程1(想要图像)

  • (通过管道2)唤醒并从共享存储器中绘制到目的地HDC 2

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

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

过程1使用StretchDIBits和指向映射视图内存的指针(如此处所述)。 这似乎是从内存中直接将数据传送到另一个HDC(在本例中是HDC 2)的唯一功能。 其他函数会先将它们复制到中间缓冲区,然后才能将它们传送到最终的HDC。

所以最终似乎需要转移的比特大约是一开始的两倍。 但是我认为这是一样的好,除非在进程之间共享GDI句柄是可能的。

注:我使用管道而不是信号,因为我需要传输一些额外的数据。

正如我所看到的,你有两个选择:

  1. 只将图像句柄/指针传递给其他进程,这两个进程只能在一个图像集合上工作。
  2. 将图像内容复制到其他进程并从此开始复制。

哪种方法最好取决于你的设计。 这两种方法的最佳工具是“内存映射文件”或“命名管道”。 这是你能得到的最快的。 内存映射文件可能是进程间通信的最快形式,但是却没有“客户端 – 服务器”范例构建。 所以你必须自己同步到MMF。 另一方面,命名管道的速度几乎一样快,但客户端 – 服务器范例可以直接嵌入到其中。 速度的差异主要来自于此。

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

为了快速实现基于命名管道的IPC,可以使用我的IPC实现。 这是消息导向,所以你不必担心管道技术细节。 它也使用幕后的线程池,并具有最小的额外开销。 您可以对自己进行压力测试并自行查看(典型的消息需要0.1 ms,才能完成客户机 – 服务器请求 – 响应周期)。