执行锁定文件(用于具有关键部分目的)清理的正确方法是什么

时间:2015-10-02 10:06:02

标签: php multithreading

引用flock(): removing locked file without race condition?Will flock'ed file be unlocked when the process die unexpectedly?

我生成以下代码。我的目的是只允许单个线程/单个进程在任何给定时间内运行临界区代码。

<?php

// Exclusive locking based on function parameters.
$lockFileName = '/tmp/cheok.lock';
// Create if doesn't exist.
$lockFile = fopen($lockFileName, "w+");

if (!flock($lockFile, LOCK_EX)) {
    throw new \RumtimeException("Fail to perform flock on $lockFileName");
}

echo "start critical section...\n";
sleep(10);
echo "end critical section.\n";

// Warning: unlink(/tmp/cheok.lock): No such file or directory in
unlink($lockFileName);
flock($lockFile, LOCK_UN);

我会一直收到警告

  

警告:取消链接(/tmp/cheok.lock):

中没有此类文件或目录

当第二个等待进程继续执行时,第一个进程已经删除了物理磁盘文件。第二个进程尝试unlink文件,该文件已被第一个进程删除。

而且,如果第三个进程加入,并在第二个进程尝试执行fopen时尝试执行unlink,该怎么办?

简而言之,执行锁定文件清理的正确方法是什么?

2 个答案:

答案 0 :(得分:3)

问题标有,因此我将在使用pthreads的多线程上下文中回答问题。

首先,关于文件锁定。 PHP手册未能完全解释咨询锁是什么。

取自flock

的手册页
  

flock()仅提供咨询锁;给定对文件的适当权限,进程可以自由地忽略flock()的使用并对文件执行I / O.

在一个充满了同时不了解权限的人的生态系统中,并使用cron作业来执行长时间运行的脚本,这可能是导致很多痛苦的原因......虽然没有人真正知道它。

在多线程(使用pthreads)的上下文中,您希望远离文件锁定,pthreads为实现互斥提供了更优越的API。

以下是创建多个线程并实现互斥的示例代码:

<?php
class Test extends Thread {

    public function __construct(Threaded $monitor) {
        $this->monitor = $monitor;
    }

    public function run () {
        $this->monitor->synchronized(function(){
            for ($i = 0; $i < 1000; $i++)
                printf("%s #%lu: %d\n",
                    __CLASS__, $this->getThreadId(), $i);
        });
    }

    private $monitor;
}

$threads = [];
$monitor = new Threaded();
for ($i = 0; $i < 8; $i++) {
    $threads[$i] = new Test($monitor);
    $threads[$i]->start();
}

foreach ($threads as $thread) 
    $thread->join();

因为所有线程共享相同的$monitor,所以您可以使用Threaded对象内置的同步来实现可靠的互斥,从而使输出类似于:

Test #140561163798272: 0
<-- snip for brevity -->
Test #140561163798272: 999
Test #140561151424256: 0
<-- snip for brevity -->
Test #140561151424256: 999
Test #140561138841344: 0
<-- snip for brevity -->
Test #140561138841344: 999
Test #140561059149568: 0
<-- snip for brevity -->
Test #140561059149568: 999
Test #140561050756864: 0
<-- snip for brevity -->
Test #140561050756864: 999
Test #140561042364160: 0
<-- snip for brevity -->
Test #140561042364160: 999
Test #140561033971456: 0
<-- snip for brevity -->
Test #140561033971456: 999
Test #140561025578752: 0
<-- snip for brevity -->
Test #140561025578752: 999

我们可以看到,每个Thread都被排除在执行Closure传递给Threaded::synchronized的代码之外。

答案 1 :(得分:0)

您可以使用出色的Process Explorer任务管理器来解锁文件。我们之前已经详细介绍了Process Explorer,因此在这里我们将直接介绍如何解锁文件。您无需先安装它-它是便携式应用程序-但需要以管理权限运行它。实际上,您可以在Process Explorer中通过单击“文件”菜单并选择“显示所有进程的详细信息”来完成此操作。