LINUX.ORG.RU
ФорумAdmin

Про пересечения «запись в файл» и «чтение из файла»

 


0

2

На нагруженных системах постоянно ловлю проблемку. Один процесс пишет в файл сигнал каждые N минут, другой процесс вычитывает сигнал из файла каждые M минут. Так вот, при N=M на нагруженных машинах часто ловлю пустоту. Тупо пусто. Ничего.

Классика типа «каждые 5» и «каждые 10» вызывает проблемы, ага. Сейчас лечу с помощью слипа на одной из сторон.

Так вот. Как насчёт «каждые 13 минут» и «каждые 10» минут? Я что-то сходу не соображу как посчитать пересечения. Помогите плиз с математикой.

Спасибо.

ЗЫ. Какой тэг-то поставить...

★★★★★

Последнее исправление: targitaj (всего исправлений: 2)
Ответ на: комментарий от targitaj

Ты горишь на совместном доступе к общему ресурсу. Поскольку, как я предполагаю, файл у тебя не защищён мьютексами и блокировками, то возникают типовые проблемы. Поэтому товарищ тебе предлагает заменить файл на fifo в качестве решения.

u5er ★★
()

Какую ещё пустоту? Опиши нормально что происходит. Если есть затруднения со словами - покажи пример кода.

Зависимости ситуации от N и M в софте без багов быть, разумеется, не должно. Так же как и костылей с подбором N и M. Осталось найти суть дефекта твоей проги и исправить его.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)

если правильно помню, то сисколлы записи и чтения в линуксе атомарные и потокобезопасные, поэтому порчи данных быть не должно. может быть сама программа что-то не то делает?

anonymous
()
Ответ на: комментарий от anonymous

сисколлы записи и чтения в линуксе атомарные и потокобезопасные

как мне пояснили, атомарное только mv. Они такое делают через временный файл. Пишут во временный файл и потом mv.

targitaj ★★★★★
() автор топика
Ответ на: комментарий от targitaj

в конце man 2 read есть ссылка на стандарт posix, где говорится, что фукции read и write должны быть атомарными, и pread, кстати тоже

другое дело, что когда ты пишешь программу «параллельно» выполняющую операции над файлом, тебе приходится учитывать позицию в файле. или если используется буферизованный ввод-вывод, то буфер надо своевременно сбрасывать.

anonymous
()

Если два процесса пишут в один файл, то нужно добавить блокировку доступа

Например, fcntl (flock). Могу добавить пример для python или perl

Ну или любой другой механизм общего доступа, на выбор

router ★★★★★
()
Ответ на: комментарий от 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 ★★★★★
()
Последнее исправление: router (всего исправлений: 1)
Ответ на: комментарий от targitaj

Желаемый результат - не ловить пустоту. Развести во времени - это просто один из возможных способов.

Ну так разведи. Пусть оба каждые 10 минут это делают, но один в HH:00, HH:10, HH:20 и т.д., а другой — в HH:05, HH:15, HH:25 и т.д.

CrX ★★★★★
()
Последнее исправление: CrX (всего исправлений: 1)

Если известно время записи, например не более 3-х минут, то можно со сдвигом сделать. В 1-ю минуту пишем, в 4-ю читаем.
Если процесс чтения запускается на той же системе на которую пишется, то можно inotify запользовать для ожидания когда запись закончится.

anc ★★★★★
()
Ответ на: комментарий от anonymous

Один процесс пишет в файл сигнал каждые N минут, другой процесс вычитывает сигнал из файла каждые M минут. Так вот, при N=M на нагруженных машинах часто ловлю пустоту.

если ты открыл не пустой файл и просто перезаписываешь данные, то ни в какой момент сторона, «параллельно» читающая файл, не получит пустоту.

создается пустой файл

непонятно зачем, но если и создаётся, то наверняка с другим именем, чтобы после записи его также атомарно, с помощью rename, переименовать в исходный. то есть тут тоже принципиально нет места для читаемой «пустоты».

anonymous
()