非阻塞flock函数的返回值和$wouldblock参数之间的区别?

2023-12-27

我试图理解非阻塞flock http://php.net//manual/en/function.flock.php和 willblock 论点

$fp = fopen('/tmp/lock.txt', 'r+'); 
if(flock($fp, LOCK_EX | LOCK_NB, $wouldblock)) {
  echo 'Lock obtained';
}
else{
  echo 'Unable to obtain lock';
}
fclose($fp);

文档中有关于 willblock 的说明:

如果锁会阻塞(EWOULDBLOCK errno 条件),则可选的第三个参数设置为 1。

在测试环境中重现并发情况,如果另一个进程获得了锁,flock 函数将立即返回 FALSE(非阻塞)

那么我为什么要关心$会阻止value 如果非阻塞模式下的flock函数的返回值allready告诉我无法获得锁?

我无法理解flock函数返回FALSE和$wouldblock参数设置为1之间的区别,以及$wouldblock参数的用途。


这是因为flock()可能失败不仅是因为在其他地方已经获得了锁。 在这种情况下,它不会阻塞等待锁被释放,但会立即返回 false。换句话说,与LOCK_NB如果flock返回false并且wouldblock=1那么这意味着它试图获得锁但它已经在其他地方获得了。但如果蜂拥而至LOCK_NB返回 false 且 willblock=0 那么这意味着发生了非常糟糕的事情,flock 甚至没有考虑等待获得锁,因为这是完全不可能的。

查看这段代码(这也是一个要点 https://gist.github.com/arvenil/a1d273f5287ce8e1f4df):

<?php
// Let's create /tmp/ninja-lock1.txt ...
$fp0 = fopen('/tmp/ninja-lock1.txt', 'c');
// ... and close it imiedietly
fclose($fp0);

// File handler $fp0 was closed so flock()
// is unable to use it to gain lock.
// It will fail with wouldblock set to 0
// as it doesn't make sense to wait on unusable file handle.
//
// BTW flock() throws in such case warning "x is not a valid stream resource".
// Just for the purpose of clear output from this example
// I've suppressed it with @ - don't use @ in production
$flockResult = @flock($fp0, LOCK_EX | LOCK_NB, $wouldblock);
printf("flock=%b; wouldblock=%d (Acquire lock: %s)\n", $flockResult, $wouldblock, "failure, broken file handle");

// Two handlers for /tmp/ninja-lock2.txt
// to show flock() blocking result.
$fp1 = fopen('/tmp/ninja-lock2.txt', 'c');
$fp2 = fopen('/tmp/ninja-lock2.txt', 'c'); 

// Nobody is locking on /tmp/ninja-lock2.txt,
// so it will acquire lock and wouldblock will be 0
$flockResult = flock($fp1, LOCK_EX | LOCK_NB, $wouldblock);
printf("flock=%b; wouldblock=%d (Acquire lock: %s)\n", $flockResult, $wouldblock, "success");

// File is locked on $fp1 handle so flock won't acquire lock
// and wouldblock will be 1
$flockResult = flock($fp2, LOCK_EX | LOCK_NB, $wouldblock);
printf("flock=%b; wouldblock=%d (Acquire lock: %s)\n", $flockResult, $wouldblock, "failure, already acquired somewhere else");

// Result:
// $ php flock.php 
// flock=0; wouldblock=0 (Acquire lock: failure, broken file handle)
// flock=1; wouldblock=0 (Acquire lock: success)
// flock=0; wouldblock=1 (Acquire lock: failure, already acquired somewhere else)
?>

另外,为了消除未来读者的任何困惑,值得注意的是,检查EWOULDBLOCK只对flock()有意义LOCK_NB标志,就像在阻塞模式下一样,它要么成功并阻塞,要么失败但不阻塞。

您可以通过查看来确认这一点群的 php 源代码 https://github.com/php/php-src/blob/af6c11c5f060870d052a2b765dc634d9e47d0f18/ext/standard/flock_compat.c#L48:

PHPAPI int php_flock(int fd, int operation)
#if HAVE_STRUCT_FLOCK /* {{{ */
{
    struct flock flck;
    int ret;

    flck.l_start = flck.l_len = 0;
    flck.l_whence = SEEK_SET;

    if (operation & LOCK_SH)
        flck.l_type = F_RDLCK;
    else if (operation & LOCK_EX)
        flck.l_type = F_WRLCK;
    else if (operation & LOCK_UN)
        flck.l_type = F_UNLCK;
    else {
        errno = EINVAL;
        return -1;
    }

    ret = fcntl(fd, operation & LOCK_NB ? F_SETLK : F_SETLKW, &flck);

    if (operation & LOCK_NB && ret == -1 && 
            (errno == EACCES || errno == EAGAIN))
        errno = EWOULDBLOCK;

    if (ret != -1) ret = 0;

    return ret;
}

EWOULDBLOCK仅当operation & LOCK_NB && ret == -1 && (errno == EACCES || errno == EAGAIN).

如果您对实施更感兴趣,您还可以阅读fcntl 的手册页 http://www.linuxmanpages.com/man2/fcntl.2.php,大部分是关于F_SETLK and F_SETLKW:

F_SETLK

对 l_whence 指定的字节获取锁(当 l_type 为 F_RDLCK 或 F_WRLCK 时)或释放锁(当 l_type 为 F_UNLCK 时), 锁的 l_start 和 l_len 字段。如果冲突的锁被持有 另一个进程,此调用返回 -1 并将 errno 设置为 EACCES 或 再次。

F_SETLKW

与 F_SETLK 一样,但如果文件上持有冲突锁,则等待该锁被释放。如果捕获到信号 等待,然后调用被中断并且(在信号处理程序之后 已返回)立即返回(返回值 -1 并设置 errno 至 EINTR)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

非阻塞flock函数的返回值和$wouldblock参数之间的区别? 的相关文章

  • 使用 Laravel 4 验证多个文件上传

    如何在 Laravel 4 中验证上传文件的数组 我已将其设置为允许多个文件 并且已测试这些文件是否存在于 Input file files 数组中 但如何验证每个文件呢 这是我尝试过的 notesData array date gt In
  • ORDER BY 字段内的 MySQL 子查询。 (没有内连接)

    有很多与此相关的问题 但都具有使用内部联接的相同答案 这 我认为 在这里是不可能的 如果我错了请告诉我 我现在正在做的是调用两个不同的 mysql 查询来获取结果 它工作完美 db gt query SELECT FROM meta WHE
  • Zend Framework 生成唯一的字符串

    我想生成一个唯一的 4 6 个字符长的字母数字字符串 以便与每个记录 用户 一起保存在数据库中 db 字段具有唯一索引 因此尝试保存预先存在的字符串会生成错误 现在我正在生成一个随机字符串并使用 try catch 因此在添加新记录时如果抛
  • openssl_pkey_get_details($res) 不返回公共指数

    我在用着这个例子 https stackoverflow com a 12575951 2016196使用 php 生成的密钥进行 javascript 加密openssl图书馆 但是 details openssl pkey get de
  • Laravel 从 5.6 升级到 Laravel 6

    我有一个项目https github com javedbaloch4 Laravel Booking https github com javedbaloch4 Laravel Booking发展于Laravel 5 6现在我想将其升级到
  • 单词之间没有空格的语言(例如亚洲语言)中的断词?

    我想让 MySQL 全文搜索适用于日语和中文文本以及任何其他语言 问题在于这些语言以及可能其他语言通常在单词之间没有空格 当您必须键入与文本中相同的句子时 搜索没有用 我不能只在每个字符之间添加空格 因为英语也必须有效 我想用 PHP 或
  • 如何解压 PHP/Lumen/Laravel 的 gzip 请求?

    我收到来自第三方的 gzip 编码文本请求 1mb 所以这是有道理的 我的测试路线 router gt post testgzip function Illuminate Http Request request decompressed
  • MySQL/PDO::quote() 尽管使用 PDO::PARAM_INT 参数,但仍在整数周围加上引号

    无论我传递给什么值 数据类型对 它都会出现 pdo gt quote value type 它总是将其引用为字符串 echo pdo gt quote foo PDO PARAM STR foo as expected echo pdo g
  • 在 php 中为类自动生成 getter 和 setter 的最佳方法是什么? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我经常创建一个包含一些私有变量的类 当设置此类的实例时 应该可以使用 getter 和 setter 填充该类的所有变量 有没有一种简单的方法可
  • PHP 会话不适用于游戏

    我正在尝试模仿一款名为 SKUNK 用骰子玩 的游戏来完成一项作业 我无法让会话正常工作 这是我第一次使用 PHP 我还被告知无需会议即可完成 这是我的代码
  • 生成大随机数 php [重复]

    这个问题在这里已经有答案了 我想使用 PHP 生成一个包含 75 个字符的数字 我到处寻找 但一无所获 除了这个 http dailycoding com tools RandomNumber aspx http dailycoding c
  • 如何从父类函数访问子类中定义的常量?

    我从 php net 看到这个例子 但 c MY CONST 仅在 5 3
  • 蛋糕控制台 2.2.1:烘焙错误

    运行 MAMP 的 OSX 机器 CakePHP 2 2 1 已正确安装和配置 这意味着当我浏览到 Index php 文件时 所有绿色条都显示出来 我已经完成了博客教程 并且正在开发我的第二个应用程序 其中脚手架已启动并运行 现在我第一次
  • 使用 preg_replace 仅替换第一个匹配项

    我有一个结构类似于以下的字符串 aba aaa cba sbd dga gad aaa cbz 该字符串每次都可能有点不同 因为它来自外部源 我只想替换第一次出现的 aaa 但其他人则不然 是否可以 可选的第四个参数预替换 http php
  • preg_match_all 查询仅显示有问题的外部组

    我无法弄清楚如何只显示 preg 查询的外部组级别 我会给你一个例子 preg match all start end input matches 这个输入start1 start2 2end 1end产生这个输出start1 start2
  • “使用未定义常量”注意,但该常量应该被定义

    共有三个文件 common php controller php 和 user php 文件 common php 如下所示 文件controller php看起来像 文件 user php 如下所示 执行脚本时 会给出通知 注意 使用未定
  • Woocommerce 结账自定义选择字段

    我有以下功能 将选择列表添加到 woo commerce 结账表单中 woocommerce form field airport pickup array type gt select class gt array airport pic
  • 在 apache docker 容器中运行虚拟主机

    我在同一个 apache 容器中有两个 php 应用程序 我试图在端口上运行其中一个应用程序 因为它需要通过根域而不是子文件夹进行访问 我想在端口 8060 上运行应用程序 我尝试使用 apache 虚拟主机执行此操作 但它不会加载页面 h
  • PHP 中只保留数组的前 N ​​个元素? [复制]

    这个问题在这里已经有答案了 有没有办法只保留数组的前 N 个 例如 10 个 元素 我知道有array pop 但是有没有更好 更优雅的方法呢 您可以使用array slice http php net array slice or arr
  • 内部 while 循环不工作

    这是我项目网页上的代码片段 这里我想显示用户选择的类别 然后想显示属于该类别的主题 在那里 用户可以拥有多个类别 这没有问题 我可以在第一个 while 循环中打印所有这些类别 问题是当我尝试打印主题时 结果只显示一行 但每个类别中有更多主

随机推荐