Questo perché flock()
potrebbe non riuscire non solo perché il blocco è già stato acquisito da qualche altra parte. In tal caso non bloccherebbe l'attesa del rilascio del blocco, ma restituirà immediatamente false. In altre parole con LOCK_NB
se flock restituisce false e wouldblock = 1 vuol dire che ha cercato di ottenere il lock ma è già stato acquisito da qualche altra parte. Ma se il gregge con LOCK_NB
restituisce false e wouldblock = 0 significa che qualcosa di veramente brutto può accadere e lo stormo non ha nemmeno pensato di aspettare per ottenere il lock in quanto ciò era completamente impossibile.
Partenza questo codice (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)
?>
Anche solo per cancellare qualsiasi confusione di futuri lettori vale la pena notare che il controllo EWOULDBLOCK
ha senso solo per il gregge() con LOCK_NB
la bandiera, come in modalità di blocco è o successo e blocco o fallimento e nessun blocco.
È possibile confermare questa, cercando in 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
è impostato solo se operation & LOCK_NB && ret == -1 && (errno == EACCES || errno == EAGAIN)
.
Se siete più interessati a realizzazione si può anche leggere man page of fcntl, per lo più le parti su F_SETLK
e F_SETLKW
:
F_SETLK
acquisire un blocco (quando L_TYPE è F_RDLCK o F_WRLCK) o rilasciare un blocco (quando l_type è F_UNLCK) sui byte specificati dai campi l_whence, l_start e l_len del blocco. Se un blocco in conflitto è trattenuto da un altro processo, questa chiamata restituisce -1 e imposta errno su EACCES o EAGAIN.
F_SETLKW
Per quanto riguarda F_SETLK, ma se un blocco in conflitto si svolge sul file, quindi attendere che il blocco per essere rilasciato.Se un segnale viene rilevato mentre è in attesa, la chiamata viene interrotta e (dopo che il gestore di segnale è ritornato) restituisce immediatamente (con valore restituito -1 ed errno impostato su EINTR ).
bella risposta, apprezzo che tu abbia segnalato il codice sorgente PHP – nulll
Quel link alla pagina man non funziona più, ma http://www.manpages.info/linux/fcntl.2.html è presumibilmente lo stesso contenuto. Ma quello dice "Dal kernel 2.0, non c'è interazione tra i tipi di lock posti da flock (2) e fcntl (2)," quindi mi chiedo se sia ancora rilevante. –