使用 XPC 在 macOS 上快速共享内存

Fast shared memory on macOS using XPC

我有两个 GUI 应用程序,它们使用共享内存(8 个内存实例,每个 ~100MB)并频繁 read/write 操作,其中一个应用程序(“服务器”)写入内存,另一个从内存中读取. 在 Windows 上,“服务器”应用程序使用 CreateFileMappingA 函数创建共享内存,而另一个应用程序使用 OpenFileMappingA 从中读取。通过 MapViewOfFile 访问缓冲区。锁定是通过命名的互斥锁完成的。

现在我正在寻找一种在 macOS 上实现它的方法。 XPC(尤其是 xpc_shmem_map)似乎很适合,但我不完全理解它是如何工作的。从文档和其他来源 (https://developer.apple.com/forums/thread/126716) 看来,我们似乎总是(?)必须创建一个服务作为两个应用程序之间的桥梁?还是一个应用程序可以充当“服务器”(如 Windows)?

在 macOS(非沙盒)上以最少的复制在两个应用程序之间共享内存的最佳方式是什么?

此致,

两个应用程序本身无法通过 XPC 直接相互通信。如果您需要在 macOS 上的两个应用程序之间安全地共享内存,XPC 可能是您的最佳选择 - 它只需要一些额外的设置。

这里要理解的核心概念是建立XPC连接只有两种方式:

  1. 正在连接到由 launchd 管理的命名服务。
  2. 正在连接到 XPC 端点。但是,进程访问与另一个服务中的侦听器连接关联的 XPC 端点的唯一方法是通过 另一个 XPC 连接。

您不能让一个 GUI 应用程序通过 XPC 直接连接到另一个 GUI 应用程序的原因是您的两个 GUI 应用程序都不会由 launchd 管理。如果您想知道,我的 GUI 应用程序可以由 launchd 管理吗?答案是不; launchd 只管理服务(动态启动,如果需要系统资源可以终止)。

您需要执行此操作的方法是:

  1. 创建 Launch Agent。 (理论上您可以创建一个启动守护进程,但没有充分的理由 — 您不需要 root 权限来执行您要执行的操作。)
  2. 安装启动代理 vend a XPC Mach service。 (这与我在描述核心概念时上面的#1 相对应。)
  3. 让您的一个 GUI 应用程序创建一个 anonymous listener connection. Then get that listener's endpoint
  4. 让该 GUI 应用程序向您的 Launch Agent 发送其端点。
  5. 让您的其他 GUI 应用程序向您的启动代理请求端点。
  6. 有其他 GUI 应用程序 create a connection using that endpoint

此时您的两个 GUI 应用程序可以直接相互通信。

我描述的有点过于简单化了。例如,您可以采用一种设计,其中它们都创建一个匿名侦听器连接,将其发送到 Launch Agent,如果另一个应用程序已经存在,那么它可以 return 那个。为避免 Launch Agent 内部的竞争条件,您可以 DispatchQueue 序列化其对来自 GUI 应用程序的请求的处理。

仅供参考,我链接到 API 的 Objective-C 版本,因为你的 post 标记为 nsxpcconnection。然而,对于所有这些,也有 C API 等价物。如果您有 cross-platform 代码库,您可能会发现 C API 更容易集成。