6

在我的 Linux 服务器上,我需要同步多个用 BASH 和 PHP 编写的脚本,以便其中只有一个能够启动系统关键作业,这是一系列 BASH/PHP 命令,如果由两个或多个脚本同时执行。根据我在 C++ 中使用多线程的经验,我熟悉互斥锁的概念,但是如何为在不同进程中运行并且当然不是用 C++ 编写的一堆脚本实现互斥锁?

好吧,想到的第一个解决方案是确保每个脚本最初都创建一个“锁定标志”文件,让其他脚本知道该作业已“锁定”,然后在完成作业后删除该文件。但是,正如我所看到的,文件写入读取操作必须是完全原子的,才能让这种方法以 100% 的概率起作用,并且同样的要求也适用于任何其他同步方法。而且我很确定文件写入/读取操作不是原子的,它们至少在所有现有的 Linux/Unix 系统中都不是原子的。

那么同步并发 BASH和PHP 脚本最灵活可靠的方法是什么?

4

3 回答 3

2

我不是 PHP 程序员,但文档说它提供了flock您可以使用的可移植版本。第一个示例片段看起来非常接近您想要的。尝试这个:

<?php

$fp = fopen("/tmp/lock.txt", "r+");

if (flock($fp, LOCK_EX)) {  // acquire an exclusive lock

    // Do your critical section here, while you hold the lock

    flock($fp, LOCK_UN);    // release the lock
} else {
    echo "Couldn't get the lock!";
}

fclose($fp);

?>

请注意,默认情况下flock会等待直到它可以获取锁。LOCK_EX | LOCK_NB如果您希望它在程序的另一个副本已经在运行的情况下立即退出,您可以使用。

使用名称“/tmp/lock.txt”可能是一个安全漏洞(我不想想太多来决定它是否真的存在),因此您可能应该选择一个只能由您的程序写入的目录。

于 2012-11-10T06:52:24.227 回答
1

您可以使用flock以原子方式锁定您的标志文件。-e选项是获取排他锁。

从手册页:

默认情况下,如果不能立即获得锁,flock 会一直等待,直到锁可用。

因此,如果您所有的 bash/php 脚本都试图以独占方式锁定文件,那么只有一个可以成功获取它,其余脚本将等待锁定。

如果您不想等待,请使用-w超时。

于 2012-11-07T11:16:57.713 回答
0

Bash 中基于fuser的锁(它保证没有两个进程同时访问受保护的资源,但即使没有进程访问资源也可能导致负锁定尝试,尽管几乎不可能):

#!/bin/bash
set -eu
function mutex {
 local file=$1 pid pids
 exec 8>>"$file"
 { pids=$(/sbin/fuser -f "$file"); } 2>&- 9>&-
 for pid in $pids; do
   [[ $pid = $$ ]] && continue
   exec 8>&-
   return 1 # locked by other pid
 done
}
于 2012-11-07T13:12:22.527 回答