LINUX.ORG.RU

История изменений

Исправление router, (текущая версия) :

  • писатели запрашивают exclusive lock

    • чтобы убедиться, что никто другой не будет обращаться к файлу
    • но писатель не получит свой exclusive lock, пока остальные не завершат доступ к файлу. И писатели, и читатели
  • читатели запрашивают shared lock

    • несколько читателей могут работать одновременно
    • но если с файлом работает писатель, то читатели будут ждать, пока тот завершит свои дела

Честно говоря, не помню что будет, если пришёл новый читатель, а писатель ЖДЁТ exclusive lock. Вроде бы новые читатели встанут в очередь за писателем

Обычно не нужно специально снимать блокировку - при закрытии файла она сама исчезает

  1. perl

perldoc -f lock


# можно и без него, но тогда константы
#   LOCK_SH, LOCK_EX, LOCK_UN придется объявлять самим
use Fcntl;

sub write_data($$) {
    my $filename = shift;
    my $data = shift;
    open DATAFILE, "+> $filename";
    flock(DATAFILE, Fcntl::LOCK_EX);  # LOCK_EX = 2

    # тут писатель работает с файлом

    close DATAFILE;
}

sub read_data($) {
    my $filename = shift;
    my $data;

    if ( -f $filename ){
        open DATAFILE, "$filename";
        flock(DATAFILE, Fcntl::LOCK_SH);  # LOCK_SH = 1

        # тут читатель работает с файлом

        close DATAFILE;
    } else {
        # нет файла. Может быть, писатели ещё не запущены
        # можно выкинуть ошибку или вернуть дефолтные данные
    };
    return $data;
}

# можно ещё использовать неблокирующий flock
# который только проверит возможность получения lock
# и если сразу не получил - вернет ошибку
# например, если нужно запускать только одну копию программы,
##  if ( flock( $lock_file, Fcntl::LOCK_EX | Fcntl::LOCK_NB ) ) {
##      log_info("got lock, running...");
##  } else {
##      log_info("can't get lock, terminating...")
##  }

  1. python

https://docs.python.org/3/library/fcntl.html

import fcntl


def write_data(filename, data):
    with open(filename, "a") as datafile:
        fcntl.flock(datafile, fcntl.LOCK_EX)

        # тут писатель работает с файлом

def read_data(filename):
    with open(filename, "r") as datafile:
        fcntl.flock(datafile, fcntl.LOCK_SH)

        # тут читатель работает с файлом

# то же самое про неблокирующую проверку lock, что и для perl

# ну и можно добавить вызов close вручную,
# чтобы не ждать, пока придёт сборщик мусора
  1. bash

работает через системный вызов. только если он есть (в linux есть)

man 1 flock

там хорошие примеры, добавлять вроде ничего не нужно

Исходная версия router, :

  • писатели запрашивают exclusive lock

    • чтобы убедиться, что никто другой не будет обращаться к файлу
    • но писатель не получит свой exclusive lock, пока остальные не завершат доступ к файлу. И писатели, и читатели
  • читатели запрашивают shared lock

    • несколько читателей могут работать одновременно
    • но если с файлом работает писатель, то читатели будут ждать, пока тот завершит свои дела

Честно говоря, не помню что будет, если пришёл новый читатель, а писатель ЖДЁТ exclusive lock. Вроде бы новые читатели встанут в очередь за писателем

Обычно не нужно специально снимать блокировку - при закрытии файла она сама исчезает

  1. perl

perldoc -f lock


# можно и без него, но тогда константы
#   LOCK_SH, LOCK_EX, LOCK_UN придется объявлять самим
use Fcntl;

sub write_data($$) {
    my $filename = shift;
    my $data = shift;
    open DATAFILE, "+> $filename";
    flock(DATAFILE, Fcntl::LOCK_EX);  # LOCK_EX = 2

    # тут писатель работает с файлом

    close DATAFILE;
}

sub read_data($) {
    my $filename = shift;
    my $data;

    if ( -f $filename ){
        open DATAFILE, "$filename";
        flock(DATAFILE, Fcntl::LOCK_SH);  # LOCK_SH = 1

        # тут читатель работает с файлом

        close DATAFILE;
    } else {
        # нет файла. Может быть, писатели ещё не запущены
        # можно выкинуть ошибку или вернуть дефолтные данные
    };
    return $data;
}

# можно ещё использовать неблокирующий flock
# который только проверит возможность получения lock
# и если сразу не получил - вернет ошибку
# например, если нужно запускать только одну копию программы,
##  if ( flock( $lock_file, Fcntl::LOCK_EX | Fcntl::LOCK_NB ) ) {
##      log_info("got lock, running...");
##  } else {
##      log_info("can't get lock, terminating...")
##  }

  1. python

https://docs.python.org/3/library/fcntl.html

import fcntl


def write_data(filename, data):
    with open(filename, "a") as datafile:
        fcntl.flock(store_file, fcntl.LOCK_EX)

        # тут писатель работает с файлом

def read_data(filename):
    with open(filename, "r") as datafile:
        fcntl.flock(store_file, fcntl.LOCK_SH)

        # тут читатель работает с файлом

# то же самое про неблокирующую проверку lock, что и для perl

# ну и можно добавить вызов close вручную,
# чтобы не ждать, пока придёт сборщик мусора
  1. bash

работает через системный вызов. только если он есть (в linux есть)

man 1 flock

там хорошие примеры, добавлять вроде ничего не нужно