Разница между возвращаемым значением неблокирующей функции стада и аргументом $ beblock?

Я пытаюсь понять не блокирующую стаю и аргумент beblock

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

Документация говорит о блокировке:

Необязательный третий аргумент устанавливается равным 1, если блокировка блокируется (условие ошибки EWOULDBLOCK).

Воспроизведение в тестовой среде параллельного условия, если другой процесс приобрел блокировку, функция стаи будет немедленно возвращать FALSE (не блокируя)

Итак, почему мне должно быть нужно значение $ beblock, если возвращаемое значение функции flock в неблокирующем режиме allready сообщает мне, что блокировка не может быть получена?

Я не могу получить разницу между функцией flock, возвращающей FALSE, и аргументом $ beblock, установленным в 1, и для аргумента $ beblock полезно использовать.

Это связано с тем, что flock() может выйти из строя не только потому, что замок уже получен где-то в другом месте. В таком случае он не блокирует ожидание блокировки, но сразу же возвращает false. Другими словами, с LOCK_NB если flock возвращает false и willblock = 1, значит, он попытался получить блокировку, но он уже приобретен где-то в другом месте. Но если flock с LOCK_NB вернет false и willblock = 0, то это означает, что что-то действительно плохое, и стая даже не рассматривала возможность ожидания блокировки, поскольку это было совершенно невозможно.

Проверьте этот код ( вот и суть ):

 <?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 для 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 устанавливается только в том случае, если operation & LOCK_NB && ret == -1 && (errno == EACCES || errno == EAGAIN) .

Если вас больше интересует реализация, вы также можете прочитать man-страницу fcntl , в основном части F_SETLK и F_SETLKW :

F_SETLK

Приобретите блокировку (когда l_type – F_RDLCK или F_WRLCK) или отпустите блокировку (когда l_type – F_UNLCK) в байтах, заданных полями l_whence, l_start и l_len блокировки. Если конфликтующая блокировка удерживается другим процессом, этот вызов возвращает -1 и устанавливает errno в EACCES или EAGAIN.

F_SETLKW

Что касается F_SETLK, но если в файле хранится конфликтная блокировка, подождите, пока эта блокировка будет выпущена. Если сигнал улавливается во время ожидания, то вызов прерывается и (после возврата обработчика сигнала) возвращается немедленно (с возвратным значением -1 и errno, установленным в EINTR).