Что такое блокировка файлов в PHP [duplicate]

В главных ответах на этой странице используются слишком простые примеры, такие как объект с одним свойством (например, {name: value}). Я думаю, что простой, но реальный пример жизни может помочь кому-то.

Итак, это JSON, возвращенный API-интерфейсом Google Translate:

{
  "data": 
     {
        "translations": 
          [
            {
              "translatedText": "Arbeit"
             }
          ]
     }
}

Я хочу получить значение атрибута «translText», например. «Arbeit» с использованием Google Gson.

Два возможных подхода:

  1. Получить только один необходимый атрибут
    String json  = callToTranslateApi("work", "de");
    JsonObject jsonObject = new JsonParser().parse(json).getAsJsonObject();
    return jsonObject.get("data").getAsJsonObject()
            .get("translations").getAsJsonArray()
            .get(0).getAsJsonObject()
            .get("translatedText").getAsString();
    
  2. Создать объект Java из JSON
    class ApiResponse {
        Data data;      
        class Data {
            Translation[] translations;         
            class Translation {
                String translatedText;
            }
         }
     }
    
    ...
     Gson g = new Gson();
     String json =callToTranslateApi("work", "de");
     ApiResponse response = g.fromJson(json, ApiResponse.class);
     return response.data.translations[0].translatedText;
    
6
задан nulll 26 June 2014 в 08:57
поделиться

1 ответ

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

Проверьте этот код ( здесь также 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)
?>

Также, чтобы устранить любую путаницу будущих читателей, стоит отметить, что проверка 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).

9
ответ дан Kamil Dziedzic 27 August 2018 в 13:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: