Xcode 日志消息“flock 未能锁定列表文件”

de.*_*de. 5 macos xcode swift

在 Xcode (Apple Silicon / Xcode 12) 中运行新创建的 macOS 应用程序时,我收到此消息。

flock 无法锁定列表文件 ([project_path]/com.apple.metal/16777235_322/functions.list):errno = 35

这是什么意思?我该如何摆脱它?

小智 8

当应用程序已经在运行,或者无法正常退出并继续在后台运行时,就会发生这种情况。

尝试:

$ pkill <yourappname>
Run Code Online (Sandbox Code Playgroud)


Ol *_*Sen 2

错误消息flock failed to lock maps file: errno = 35或 (list) 表示调用flock()失败,错误代码为 35,在某些系统上对应于EAGAIN,在 macOS 上也是如此。如果文件的锁由另一个进程持有,或者该进程已达到其最大锁数,则可能会发生此错误。

典型的症状是此错误消息在日志中多次出现。这也指出了它能走到今天这一步的一个可能原因。但这是关于flock()内部工作原理的另一次讨论。

要调试此问题,您可以首先尝试确定哪个进程持有锁定。在终端中,您可以使用该lsof命令列出所有打开的文件以及打开它们的进程。例如:

$ lsof | grep maps
Run Code Online (Sandbox Code Playgroud)

这将需要几秒钟的时间,并为您提供打开映射文件的进程列表,换句话说,谁在映射/列表上持有锁。从此列表中,您可以尝试通过使用集群命令的进程 ID (PID) 来确定哪个进程持有锁定。例如:

$ flock -x -w 10 /proc/<PID>/maps
Run Code Online (Sandbox Code Playgroud)

如果flock命令成功,则持有锁的进程已释放它。如果flock命令失败,您可以尝试杀死持有锁的进程。

不错,但是如何找到 PID 呢?下面详细介绍一下。

因此,以下可以称为残酷的方法:

如果你flock()在 C 中使用 example 编写了一些东西(当你用机制做东西时也是这种情况pipe,因为这可能会干扰 /dev/null 这是一个文件的特殊情况并使用fork()dup()dup2()shmget()类似的调用)并且不知何故,你的锁定/解锁机制弄乱了你的地图,这是写入锁的地方,那么肯定pkill会帮助你。但在这样做之前,请证明有多个进程具有相同的名称 - 您会知道名称应该是什么样子,因为您自己编码了它。

如果您知道名称,则可以使用它pgrep来查找所有实例。

pgrep -x myappname
Run Code Online (Sandbox Code Playgroud)

myappname 肯定在地图列表中吗?如果是,继续,上面的命令将打印与该进程名称相对应的 PID 列表,该进程名称通常与应用程序名称相对应。

从这里你可以,这就是我将其命名为残酷的原因,只是pkill所有这些都带有

pkill -x myappname
Run Code Online (Sandbox Code Playgroud)

当然,这将迫使他们所有人立即退出。这反过来也应该释放对它们可能仍然持有的文件的锁定。但要注意 pkill-ing 不会正确释放,它只是立即退出,因此 -dealloc 方法中的编码的集群解锁也不会触发,但已使用的内存会被释放 - 这就是您所需要的。

为什么会发生这种事?好吧,您可能刚刚在开发中崩溃了您的应用程序,或者金属调试被打开,当然,这也使用了这种机制,例如管道日志。当您在没有正确释放或类似的情况下退出时,可能不会调用清理过程来释放某些文件或管道的文件锁(简称:flock),因此文件保持锁定状态。

由于具有 Metal 调试功能的 Xcode 会尝试对其映射文件设置锁定,但在每次尝试对锁定文件设置锁定时收到此错误消息之前,该文件会被锁定为崩溃遗留的问题。因此,仅仅关闭 Metal 调试是没有意义的,如果这是原因,您仍然需要解锁僵尸应用程序/进程仍在使用的文件。自己删除映射文件就像直接弄乱文件系统一样,当然会导致意外的结果。

df -l
Run Code Online (Sandbox Code Playgroud)

应该为您提供文件系统的列表,其中包含使用信息,您可以在其中读取已使用的数量。在 100% 使用 /dev/null 和类似的情况下,您可以看到是否弄乱了共享内存,在这种情况下,当您尝试在已用完的内存上获取某些文件时,flock 解锁文件也会失败。如果这一切都是通过使用管道机制发生的,那么您很可能没有刷新缓冲区,也就是说您没有从中读取数据,这反过来应该清空这样的缓冲区,这样它就无法锁定,以防它变满。

如果所有这些都没有帮助 - 你最后的手段是重新启动机器。