非阻塞的flock函数的返回值和$ wouldblock参数之间的区别? [英] Difference between return value of non-blocking flock function and the $wouldblock argument?

查看:320
本文介绍了非阻塞的flock函数的返回值和$ wouldblock参数之间的区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想了解非封锁鸡群和willblock参数

  $ fp = fopen('/ tmp / lock.txt','r +'); 
if(flock($ fp,LOCK_EX | LOCK_NB,$ wouldblock)){
echo'Lock got';
}
else {
echo'无法获取锁';
}
fclose($ fp);

文档说关于willblock:


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


在测试环境中再现并发条件,如果另一个进程已获得锁定,则flock函数将imactitatly返回FALSE



那么为什么我应该关心 $ wouldblock 的值如果flock函数的返回值在非阻塞模式allready告诉我锁lockn不能得到flock函数返回FALSE和$ wouldblock参数设置为1之间的区别,以及$ wouldblock参数是什么usefull为什么不能获得?



< 。

解决方案

这是因为 flock()锁已经在其他地方获得。
在这种情况下,它不会阻塞等待释放锁,但它会立即返回false。换句话说,如果flock返回false并且wouldblock = 1,则表示 LOCK_NB ,它意味着它尝试获得锁,但它已经被其他地方获取。但是如果flock与 LOCK_NB 返回false和wouldblock = 0,那么它意味着一些真正的坏发生,并且flock甚至没有考虑等待获得锁,因为这是完全不可能的。



查看此代码(这里也是一个提示) :

 <?php 
//让我们创建/tmp/ninja-lock1.txt ...
$ fp0 = fopen('/ tmp / ninja-lock1.txt','c');
// ...并关闭它imiedietly
fclose($ fp0);

//文件处理程序$ fp0已关闭,所以flock()
//无法使用它来获取锁。
//它将失败,并将willblock设置为0
//因为等待不可用的文件句柄没有意义。
//
// BTW flock()在这种情况下抛出警告x不是有效的流资源。
//只是为了从这个例子清除输出的目的
//我用@禁止它 - 不要在生产中使用@
$ flockResult = @flock($ fp0, LOCK_EX | LOCK_NB,$ wouldblock);
printf(flock =%b; willblock =%d(获取锁:%s)\\\
,$ flockResult,$ wouldblock,失败,

// /tmp/ninja-lock2.txt的两个处理程序
//显示flock()阻塞结果。
$ fp1 = fopen('/ tmp / ninja-lock2.txt','c');
$ fp2 = fopen('/ tmp / ninja-lock2.txt','c');

//没有人锁定/tmp/ninja-lock2.txt,
//因此它将获得锁,并且willblock将为0
$ flockResult = flock($ fp1 ,LOCK_EX | LOCK_NB,$ wouldblock);
printf(flock =%b; willblock =%d(获取锁:%s)\\\
,$ flockResult,$ wouldblock,success

//文件被锁定在$ fp1句柄,所以flock不会获取锁
//和willblock将是1
$ flockResult = flock($ fp2,LOCK_EX | LOCK_NB ,$ wouldblock);
printf(flock =%b; willblock =%d(获取锁:%s)\\\
,$ flockResult,$ wouldblock,失败,

//结果:
// $ php flock.php
// flock = 0; willblock = 0(获取锁:失败,文件句柄被破坏)
// flock = 1; willblock = 0(获取锁:成功)
// flock = 0; willblock = 1(获取锁:失败,已在别处获取)
?>

同样只是为了清除未来读者的任何混乱,值得注意的是检查 EWOULDBLOCK 只对flock()和 LOCK_NB 标志有意义,因为在阻塞模式下它是成功和块或失败, >

您可以通过查看 PHP的源代码

  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 只有操作& LOCK_NB&& ret == -1&&
(errno == EACCES || errno == EAGAIN)



如果你对实现更感兴趣, fcntl 的手册页,大部分是关于 F_SETLK F_SETLKW


F_SETLK


$ b b

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



F_SETLKW



对于F_SETLK,但如果在文件上保持冲突的锁,则等待该锁释放。如果在
等待期间捕获到信号,则调用被中断,并且(在信号处理程序
已经返回之后)立即返回(具有返回值-1并且errno将
设置为EINTR)。



I'm trying to understand non blocking flock and the wouldblock argument

$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);

Documentation says about wouldblock:

The optional third argument is set to 1 if the lock would block (EWOULDBLOCK errno condition).

Reproducing in a test enviroment the concurrent condition, if another process has gained lock, the flock function will immeditatly return FALSE (non blocking)

So why should I care about $wouldblock value if the return value of flock function in non-blocking mode allready tells me that the lock couldn't be obtained?

I can't get the difference between flock function returning FALSE and the $wouldblock argument setted to 1, and what the $wouldblock argument is usefull for.

解决方案

This is because flock() may fail not only because lock is already gained somewhere else. In such case it wouldn't block waiting for lock being released, but it would immediately return false. In other words with LOCK_NB if flock returns false and wouldblock=1 then it means, it tried to gain lock but it is already acquired somewhere else. But if flock with LOCK_NB returns false and wouldblock=0 then it means something really bad happen and flock didn't even consider waiting to gain lock as this was completely impossible.

Check out this code(here is also a gist):

<?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)
?>

Also just to clear any confusion of future readers it's worth to note that checking EWOULDBLOCK makes only sense for flock() with LOCK_NB flag, as in blocking mode it's either success and block or failure and no block.

You can confirm this by looking into php source code for flock:

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 is set only if operation & LOCK_NB && ret == -1 && (errno == EACCES || errno == EAGAIN).

If you are more interested in implementation you can also read man page of fcntl, mostly parts about F_SETLK and F_SETLKW:

F_SETLK

Acquire a lock (when l_type is F_RDLCK or F_WRLCK) or release a lock (when l_type is F_UNLCK) on the bytes specified by the l_whence, l_start, and l_len fields of lock. If a conflicting lock is held by another process, this call returns -1 and sets errno to EACCES or EAGAIN.

F_SETLKW

As for F_SETLK, but if a conflicting lock is held on the file, then wait for that lock to be released. If a signal is caught while waiting, then the call is interrupted and (after the signal handler has returned) returns immediately (with return value -1 and errno set to EINTR).

这篇关于非阻塞的flock函数的返回值和$ wouldblock参数之间的区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆