在不同运行的应用程序之间共享内存
一种在不同应用程序之间共享数据的简单方法。
引言
共享内存是一个强大的工具,现在可以轻松实现……
您有一个应用程序,我们称之为应用程序“A.exe”,您希望它将数据传递给您的应用程序“B.exe”。您将如何做到这一点?
- 您可以共享一个文件,但这会很慢,如果数据经常使用,它将给您的硬盘驱动器带来过度的压力。
- 您可以跨本地网络链接共享数据,但这只是增加了 PC 的开销。
- 您可以共享一些内存,但是如何做到呢?
例如,应用程序“A”是一个复杂的 GUI,它登录用户、读取数据库,并添加用于控制连接硬件的用户窗体控件。应用程序“B”需要在同一 PC 的另一个线程/CPU 核心上同时运行。它通过 LAN 或 USB 实时控制硬件,但需要应用程序“A”的用户数据库结果所需的数据。
实时共享内存是最好的方法。然而,这并不像听起来那么容易……
背景
PC 上的内存由操作系统完全管理,在本例中是 Microsoft Windows 7。操作系统必须在多个 CPU 核心上平衡所有不同的运行应用程序,以支持所有正在运行的“线程”。应用程序“A”的线程将不知道应用程序“B”的线程或其内存使用情况。那么我们如何分配一些内存来共享一些数据呢?
在过去的糟糕编程时代,您会输入“保留内存地址 XXX”,而在“Basic”中,您会输入诸如 PEEK
或 POKE
之类的关键字来放置数据。但是,如果您的所有应用程序都这样做,您很快就会耗尽内存,这确实发生过!
直到 .NET Framework 4,共享内存一直很难实现。但由于一些新函数,它变得非常容易,并且您的应用程序无需了解线程或内存,因为新函数会为您处理内存和线程安全。
这个新的共享内存函数就像文件一样处理;您用名称打开它们,向其中添加数据,并在不同应用程序之间共享它们。数据可以从几个字节到几个千兆字节。但是我更喜欢使用一个小的“共享内存缓冲区文件”。我的共享内存文件的任务是在我的不同应用程序之间传递变量和数据。
另一个例子:您可以有一个名为“Commands”的共享内存文件,它只有几个字节大小,由应用程序 A 发送。应用程序 B 读取命令,并从其名为“Results”的共享内存文件中回复,并将结果准备好给应用程序 A。组合是无限的,您可以拥有任意数量的运行应用程序。
如需进一步阅读,请参阅 http://msdn.microsoft.com/en-us/library/dd997372.aspx。
代码描述
代码导入了 System.IO.MemoryMappedFiles
命名空间,其中包含您控制内存映射文件所需的所有类,并等待按钮 MakeFile
或 ReadFile
的鼠标单击事件触发。
要将一些数据写入内存共享,您可以执行以下操作……
调用 MakeMemoryMappedFile()
。
首先,您声明一个对象;我使用了“File
”作为内存映射文件,您可以使用所需字节数(例如 26)“打开”它,并为其命名,我在这里使用了“MemoryFile
”。
Dim File=MemoryMappedFile.CreateOrOpen("MemoryFile",26)
请注意,我使用了“CreateOrOpen
”。如果您发现另一个应用程序已使用相同名称打开了它,这会很有用。为了更简单,您可以使用“Create
”。
接下来,我生成一个名为“bytes
”的“26 字节数组”。这将是我的字节内存缓冲区,它可以容纳我希望在应用程序之间共享的任何内容。在这种情况下,我只是将一个简单的计数放入“Bytes”中,即 1,2,3,4……这都在“For Next”循环中完成。
现在我们需要使我们的共享内存“MemoryFile
”对我们的其他应用程序可见。这是通过使用我称为“writer”的对象并调用“CreatViewAccessor
”方法来完成的。这使得内存文件数据“Viewable
”。您可以设置您的查看应用程序想要看到的开始位置和大小,我使用了“bytes Array
”的起始位置 0 和“bytes Array
”的长度(26)。
Using writer = File.CreateViewAccessor(0, bytes.Length)
在“MemoryFile
”打开并可见之后,唯一需要做的就是将我们的字节数组写入共享内存,这可以通过以下方式完成:
writer.WriteArray(Of Byte)(0, bytes, 0, bytes.Length)
要读取共享内存中的数据,您需要执行以下操作……
调用 ReadMemoryMappedFile()
。
我在这里的对象“File
”用于“打开”一个“现有”的共享内存文件,我们在上面的方法中打开了它,名为“MemoryFile
”。
Using file = MemoryMappedFile.OpenExisting("MemoryFile")
这里 Try
和 Catch
对我们很重要,因为共享内存文件可能不存在,所以我捕获异常并简单地显示一个消息框,说明它不存在。您可以在此处添加自己的处理程序。注意:与标准文件处理不同,此类不支持“If.exist
”。
reader 打开后,类需要知道您想访问和查看什么。这是通过我称为“reader
”的对象并使用“CreateViewAccessor
”方法以及开始和要访问的字节数来完成的。但我先准备了一个缓冲区来保存要读取的数据字节,我也称之为“bytes
”,因为我知道我发送了多少字节 - 我已将其硬编码为相同大小(26)。
然后将缓冲区加载为
reader.ReadArray(Of Byte)(0, bytes, 0, bytes.Length)
最后,我将字节转换为字符串显示在一个文本框中。您的代码可以解析字节以获取命令或数据以供进一步操作或事件。您应该关闭内存,就像您处理文件一样。在此示例中,我将其保持打开状态,以便可以递归调用以进行演示。
这里显示的代码只是一种形式;同一代码在另一个名为 form 2 的应用程序中重复,只是写入数组中的数据有所更改,以显示您可以更改它。
Using the Code
演示的 VB.NET 应用程序是同一个 VS2010 解决方案中的两个项目。它们各自包含一个窗体。我们在两个项目中都使用了 System.IO.MemoryMappedFiles
命名空间,我的示例使用了您系统内存中的几个字节。
单击 Makefile 按钮时,应用程序 Form1
会写入几个字节。例如,值为 1, 2, 3, 4……等等。您可以在同一窗体的文本框中通过 ReadFile 按钮读回它们,或者更重要的是,可以从另一个应用程序 Form2
的 Readfile 按钮读回它们。
应用程序 Form2
的 Makefile 按钮将一些不同的数据(增加 10)放入同一个共享内存文件中,这样您就可以看到读取不同数据是多么容易。
一旦您玩过这个演示,您就应该能够将其改编到您自己的应用程序中……
Imports System
Imports System.IO
Imports System.IO.MemoryMappedFiles
''' <summary>
''' Demo Form 1
''' </summary>
''' <remarks>
''' By David Rathbone 18/08/2011
''' Many thanks to Microsoft
''' </remarks>
Public Class Form1
''' <summary>
''' Write Memory
''' </summary>
''' <remarks></remarks>
Private Sub MakeMemoryMappedFile()
Dim File = MemoryMappedFile.CreateOrOpen("MemoryFile", 26)
Dim bytes = New Byte(25) {}
For i As Integer = 0 To bytes.Length - 1
bytes(i) = i + 1
Next
Using writer = File.CreateViewAccessor(0, bytes.Length)
writer.WriteArray(Of Byte)(0, bytes, 0, bytes.Length)
End Using
End Sub
''' <summary>
''' Read Memory
''' </summary>
''' <remarks></remarks>
Private Sub ReadMemoryMappedFile()
Try
Using file = MemoryMappedFile.OpenExisting("MemoryFile")
Using reader = file.CreateViewAccessor(0, 26)
Dim bytes = New Byte(25) {}
reader.ReadArray(Of Byte)(0, bytes, 0, bytes.Length)
TextBox1.Text = ""
For i As Integer = 0 To bytes.Length - 1
TextBox1.AppendText(CStr(bytes(i)) + " ")
Next
End Using
End Using
Catch noFile As FileNotFoundException
TextBox1.Text = "Memory-mapped file does not exist."
Catch Ex As Exception
End Try
End Sub
''' <summary>
''' Button Make File Click event
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Private Sub Btn_Make_Click(sender As System.Object, e As System.EventArgs) _
Handles Btn_Make.Click
MakeMemoryMappedFile()
End Sub
''' <summary>
''' Button Read File Click event
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Private Sub Btn_Read_Click(sender As System.Object, e As System.EventArgs) _
Handles Btn_Read.Click
ReadMemoryMappedFile()
End Sub
End Class
历史
- 首个版本:2011 年 8 月 18 日。