我需要实现一个锁定方案,以便多个进程可以共享一组资源,而“特殊”进程可以获得对该组资源的独占访问权限。
这些是批处理过程:在每个事务开始时,我建议获取适当的锁,并在结束时释放它,无限循环。
flock
具有我需要的语义(LOCK_SH、LOCK_EX、LOCK_UN)。我使用 Perl Flock.pm 和一个虚拟文件进行了实验,该文件的唯一目的是进行flock
“编辑”。我对它的速度有多慢感到有点惊讶,而且从“顶部”看不出来时间花在哪里。 (它不是 CPU 限制的,即使正在执行的循环只包含 LOCK_SH 和 LOCK_UN。)我不想因过早优化而感到内疚,但我想知道flock
管理共享和共享的标准方法是否是对 *nix 中共享资源的独占访问,即使共享资源不是实际文件,或者是否存在我不知道的其他设施。
更新:@msw 正确地猜测到我(无意中)锁定了 NFS 文件而不是本地文件。使用本地文件完全消除了我所看到的性能影响。我将这个问题悬而未决,以了解更多有关“文件锁定”是否真的是解决此类问题的最佳方法的信息。
答案1
Unix 有大量的锁定系统。你找到的那个叫做 BSD 文件锁定,但是有其他文件锁定方法。除此之外,你还拥有信号量,互斥体和更多。
至于你直接提出的问题,是的,这是一个非常好的方法。不用担心需要的时间。就其本质而言,锁定是一项高开销的活动。这就是为什么在设计上花费如此多的精力无锁机制。
你的计划唯一让我烦恼的是你必须创建的虚拟文件。可能有一种更简单的方法可以达到您想要的目的:mkdir(2)
。该调用是原子的,当目录已存在时您会收到错误。相比之下,open(2)
是只有原子的O_EXCL
,这并非在任何地方都可用。如果可用,它可能无法按预期工作,因为您正在使用 NFSv2 或者因为您尚未启用NFS 文件锁定守护进程。
该方法的一个好处mkdir
是您可以通过 .shell 脚本来完成它mkdir(1)
。我看到您正在使用 Perl,但在这种情况下,它是一个内置函数,而不是外部模块。
另一个好处是它可以通过 NFS 工作而无需任何特殊帮助。您不能两次创建一个目录。
该方法的唯一问题mkdir()
是没有办法让它等待现有目录消失。也就是说,它不是阻塞锁操作。我建议你用一个计时器来包装它,以便争用锁的进程大部分时间都在休眠。我建议您让每个进程等待一段随机的窗口时间。例如,在 100 到 200 毫秒之间,通过usleep(3)
。这将创建一种形式自旋锁。