当前位置: 首页 > 知识库问答 >
问题:

为什么我的php flock在运行命令两次时没有检测到现有的锁?

薄高懿
2023-03-14

稍微解释一下,我有一个Symfony2设置。我正在使用我扩展的抽象命令类。我希望这些批次中的任何批次只能运行一次。我的目标是做一个锁文件,我打开并聚集,这样当php脚本以任何可能的方式死亡时,锁会自动释放。

为了实现这一点,我创建了一个名为Lock的类。该类扩展了SplFileObject,基本上是创建*的包装器。锁定某个位置(通常为/var/lock/*)。现在我发现这个锁有问题。我确实有一个使用fopen和flock的设置。由于某种原因,它再也检测不到它了。

我创建了一个OOP结构来做我想做的事情:

  • 确定锁文件的名称(使用文件夹)
  • 创建一个Lock对象
    • 创建目录并锁定文件,如果它们不存在
    • 调用SplFileObject::__construct()

    我不能让这个工作既没有句柄也没有spl文件对象。如果我运行脚本,让它Hibernate15秒,并在另一个控制台运行相同的脚本,我会得到一个结果,脚本设法锁定文件,flock返回true。如果我在同一个脚本中的同一个锁文件上创建2个锁对象,我在第一个锁上得到true,在第二个锁上得到false,这意味着第二次它未能获得锁。剧本似乎奏效了。

    然而,当我在两个脚本中运行2次带有2个锁的脚本时,我在两个脚本上都得到True和false...这意味着它似乎不能正确地跨脚本锁定文件:/

    有人能告诉我我做错了什么吗?我已经检查了文件名,它在我运行脚本的两次中都是相等的。我尝试了多个权限,如777, 755, 733但没有区别。

    我这样称呼它(只是课堂的一部分):

    abstract class AbstractTripolisCommand extends ContainerAwareCommand
    {
    [...]
      /**
       * Locks the current file based on environments
       *
       * @param string $application_env
       * @param string $symfony_env
       */
      private function lockCommand($application_env, $symfony_env)
      {
        $lock_name  = "tripolis/$application_env/$symfony_env/" . crc32(get_class($this));
        $lock = new Lock($lock_name, 'w+', $this->getContainer()->get('filesystem'));
        var_dump($lock->lock());
        $lock2 = new Lock($lock_name, 'w+', $this->getContainer()->get('filesystem'));
        var_dump($lock2->lock());
        // results when ran 2 times at the same time
        // bool(true)
        // bool(false)
        // when I run this script twice I expect the second run at the same time
        // bool(false)
        // bool(false)
    
        if(!$lock->lock()) {
          throw new Tripolis\Exception('Unable to obtain lock, script is already running');
        }
      }
    [...]
    }
    

    我ock.php

    namespace Something\Component\File;
    
    use Symfony\Component\Filesystem\Filesystem;
    
    /**
     * Creates a new SplFileObject with access to lock and release locks
     * Upon creation it will create the lock file if not exists
     *
     * The lock works by keeping a stream open to the lock file instead
     * of creating/deleting the lock file. This way the lock is always
     * released when the script ends or crashes.
     *
     * create a file named /var/lock/something/something.lock
     * <example>
     *   $lock = new Lock('something');
     *   $lock->lock();
     *   $lock->release();
     * </example>
     *
     * create a file named /var/lock/something/my-lock-file.lock
     * <example>
     *   $lock = new Lock('something/my-lock-file');
     *   $lock->lock();
     * </example>
     *
     * NOTE: locks that are not released are released
     * automatically when the php script ends
     *
     * @author Iltar van der Berg <ivanderberg@something.nl>
     */
    class Lock extends \SplFileObject implements Lockable
    {
      /**
       * @param string     $file_name
       * @param string     $open_mode
       * @param Filesystem $filesystem
       * @param string     $lock_directory
       */
      public function __construct($file_name, $open_mode = 'r+', Filesystem $filesystem = null, $lock_directory = '/var/lock')
      {
        $filesystem = $filesystem ?: new Filesystem();
        $file = self::touchLockFile($file_name, $lock_directory, $filesystem);
        parent::__construct($file, $open_mode);
    
      }
    
      /**
       * Returns true if the lock is placed, false if unable to
       *
       * @return boolean
       */
      public function lock()
      {
        return $this->flock(LOCK_EX | LOCK_NB);
      }
    
      /**
       * Returns true if the lock is released
       *
       * @return bool
       */
      public function release()
      {
        return $this->flock(LOCK_UN);
      }
    
      /**
       * Attempts to create a lock file for a given filename and directory
       * it will return a string if the file is touched
       *
       * @param  string     $file_name
       * @param  string     $lock_directory
       * @param  Filesystem $filesystem
       * @return string
       */
      private static function touchLockFile($file_name, $lock_directory, Filesystem $filesystem)
      {
        $lock_file_path = explode('/', $file_name);
        $lock_file      = array_pop($lock_file_path);
    
        $path = "$lock_directory/" . (empty($lock_file_path)
          ? $lock_file
          :  implode('/', $lock_file_path));
    
        $lock_file = "$path/$lock_file.lock";
    
        if(!$filesystem->exists($path) || !is_dir($path)) {
          $filesystem->mkdir($path);
        }
    
        return $lock_file;
      }
    }
    ?>
    

共有1个答案

姬高扬
2023-03-14

我敢打赌,锁或文件被销毁的时间比你想象的要早,因为拥有这些对象的函数返回了,从而使这些对象符合垃圾回收机制的条件。

 类似资料:
  • 我试图为我的类“Sinus”(用于计算浮点的Sinus)运行一个测试,但当我试图运行这个测试来生成我的Cobertura覆盖率报告时,它不起作用,我真的不知道为什么!你有什么建议或解释吗?(我使用cmd:mvn cobertura:cobertura) -这是我的测试: 结果是: 那有什么问题?有什么想法吗?这是我的pom。xml如下:

  • 问题内容: 我有以下代码: 以及其他各种方法,例如@ Before,@ After,@ Test或@AfterClass方法。 测试在启动时不会像看起来的那样失败。有谁可以帮助我吗? 我有JUnit 4.5 该方法无法立即调用注释为@before的setUp()。类def是: 问题答案: 不要扩展TestCase并同时使用注释! 如果需要使用批注创建测试套件,请使用RunWith批注,例如: (按

  • 您将自动执行著名的歌曲“墙上的99瓶XXX”。你将打印这首歌所有99个诗句的歌词。用循环!如果你不知道歌词,用谷歌查一下。 该方案应: a.如果他们不到21岁,或者他们喜欢苏打水,那么歌词是“墙上有99瓶苏打水” B.如果他们超过21岁,那么是“99瓶啤酒” 您必须使用WHILE循环,并且counter变量必须是print语句的一部分! 所以第一节是: 99瓶苏打水挂在墙上 墙上有98瓶苏打水 最

  • 我使用surefire和failsafe分别执行单元测试和集成测试。所有测试都位于文件夹中。到目前为止,我有一个集成测试类,其测试方法(用@test注释)在所有单元测试运行时从不执行。这是我的pom的摘录。xml: 我使用maven目标来运行测试。

  • 我正在尝试将一个梅文Spring靴(2.3.12)应用程序从JUnit4转换为JUnit5。我已经阅读了很多关于如何做到这一点的不同帖子。 我能够在Eclipse中执行我的JUnit5测试。 我的问题是我无法让Maven Surefire执行我的JUnit5测试。我尝试了各种配置变体。当它到达Surefire步骤时,它只执行我以前的JUnit4测试,并且简单地忽略任何JUnit5测试。我已经验证了

  • 我一直在尝试使用OpenGL2绘制一个带有纹理的平面。在Android上安装了0个ES。然而,我不断收到一个logcat错误,上面写着“GLDrawerements:没有绑定到命令的数据-忽略”(tag:emuglesv2_enc),飞机不再显示。 我的飞机: } 顶点着色器: 片段着色器: Emulator在android 5.1.1上运行。