2014-06-26 8 views
5

sto cercando di capire non bloccante flock e l'argomento wouldblock

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

documentazione dice di wouldblock:

Il terzo argomento opzionale è impostato a 1 se il blocco sarebbe bloccare (condizione errno EWOULDBLOCK).

riprodurre in un test ambiente la condizione concomitante, se un altro processo ha guadagnato di blocco, la funzione gregge sarà immeditatly restituirà FALSE (non bloccante)

Quindi perché dovrei preoccuparmi $ wouldblock valore se il il valore di ritorno della funzione flock in modalità non bloccante mi dice già che non è stato possibile ottenere il blocco?

Non riesco a ottenere la differenza tra la funzione di flock che restituisce FALSE e l'argomento $ di blocco impostato su 1, e per che l'argomento $ di blocco è utile.

risposta

8

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

+0

bella risposta, apprezzo che tu abbia segnalato il codice sorgente PHP – nulll

+0

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. –

Problemi correlati