Dies liegt daran, flock()
kann nicht nur nicht fehlschlagen, weil Sperre bereits woanders gewonnen wird. In diesem Fall würde das Warten auf das Freigeben der Sperre nicht blockiert werden, aber es würde sofort false zurückgeben. Mit anderen Worten, mit LOCK_NB
, wenn Flock falsch zurückgibt und wantblock = 1, dann bedeutet es, dass es versuchte, eine Sperre zu erreichen, aber es ist bereits woanders erworben. Aber wenn flock mit LOCK_NB
false zurückgibt und wantblock = 0, dann bedeutet das, dass etwas wirklich Schreckliches passiert und Flock hat nicht einmal daran gedacht, auf Lock zu warten, da dies völlig unmöglich ist.
überprüfen diesen Code aus (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)
?>
auch nur eine Verwechslung der zukünftigen Leser klar, es lohnt sich zu beachten, dass EWOULDBLOCK
macht nur Sinn für flock() mit LOCK_NB
Flagge überprüft, wie im blockierenden Modus Es ist entweder Erfolg und Block oder Fehler und kein Block.
Sie können dies in php source code for flock, indem Sie bestätigen:
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
gesetzt ist nur dann, wenn operation & LOCK_NB && ret == -1 && (errno == EACCES || errno == EAGAIN)
.
Wenn Sie interessieren sich mehr für die Umsetzung auch man page of fcntl lesen können, meist Teile über F_SETLK
und F_SETLKW
:
F_SETLK
eine Sperre erwerben (wenn l_type F_RDLCK oder F_WRLCK ist) oder lösen eine Sperre (wenn l_type F_UNLCK ist) für die Bytes, die durch die l_whence-, l_start- und l_len-Felder der Sperre angegeben sind. Wenn eine widersprüchliche Sperre von einem anderen Prozess gehalten wird, gibt dieser Aufruf -1 zurück und setzt errno auf EACCES oder EAGAIN.
F_SETLKW
Was F_SETLK, aber wenn eine kollidiere Sperre für die Datei gehalten wird, dann warten, dass Sperre freigegeben werden.Wenn ein Signal empfangen wird, während wartet, wird der Anruf unterbrochen und (nachdem der Signalhandler zurückgegeben wurde) sofort zurückgegeben (mit Rückgabewert -1 und errno auf auf EINTR gesetzt).
nette Antwort, ich appriciate, dass Sie die PHP-Quellcode berichtet – nulll
Dieser Mann-Link nicht mehr funktioniert, aber http://www.manpages.info/linux/fcntl.2.html ist vermutlich der gleiche Inhalt. Aber das sagt "Seit Kernel 2.0 gibt es keine Interaktion zwischen den Arten von Sperren, die von flock (2) und fcntl (2) platziert wurden", also frage ich mich, ob das noch relevant ist. –