LINUX.ORG.RU

Реализация lock-файла


0

0

Добрый день.

Ткните, пожалуйста, ссылкой на какой-нибудь HowTo по реализации lock-файлов, или подскажите, в какую сторону копать.

Что конкретно нужно:
При запуске программа смотрит, существует ли lock-файл. Если да, то каким-либо образом соединяется с уже запущенной копией, передает ей параметры командной строки и завершает работу.
Если lock-файл не существует, то создает его и начинает работу.

Проблема, собственно, в атомарности: как разрешить ситуацию, когда запускается одновременно несколько экземпляров приложения (в итоге остаться работать должно только одно из них) + если приложение создает lock файл, и его потом убивают через kill -9, то файл останется в системе...

Вообщем, думаю, все эти проблемы уже давно решены. Подскажите, пожалуйста, где можно найти это самое решение.


> Проблема, собственно, в атомарности: как разрешить ситуацию, когда запускается одновременно несколько экземпляров приложения (в итоге остаться работать должно только одно из них)

Нужно вызывать open с флагами (O_CREAT | O_EXCL). С этими флагами либо будет создан новый файл, либо вызов вернёт ошибку, если файл уже существует.

В шелле можно делать примерно так:

until ( set -C; echo -n "X" > "/path/to/my/lock/file" ) 2> /dev/null; do
sleep 0.1s # чтобы бессмысленно не грузить процессор
done

> + если приложение создает lock файл, и его потом убивают через kill -9, то файл останется в системе...


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

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

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

riYu
() автор топика

> Проблема, собственно, в атомарности: как разрешить ситуацию, когда запускается одновременно несколько экземпляров приложения

rename в пределах одной файловой системы атомарен -- то есть нужно сперва создать файл со случайным именем в той же директории, и сделать rename/mv. Если rename обломился, то лок уже создан другим.

dilmah ★★★★★
()

Может лучше просканировать /proc/PID/cmdline на наличие одноименных процессов ? если ты единственный то делай свое дело, если есть только один одноименный процесс пид который меньше твоего передавай параметры, если перед тобой два и более просто выходи - иначе вся куча одновременно запущенных процессов будет пытаться передавать свои параметры.

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

> Может лучше просканировать /proc/PID/cmdline на наличие одноименных процессов ? если ты единственный то делай свое дело, если есть только один одноименный процесс пид который меньше твоего передавай параметры, если перед тобой два и более просто выходи - иначе вся куча одновременно запущенных процессов будет пытаться передавать свои параметры.

Как это реализовать и не получить race condition?

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

>Как это реализовать и не получить race condition?

Встречный вопрос - как реализовать чтобы получить race condition ? или ты думаешь что ядро при создании процесса бросит свое дело на полпути и побежит создавать другой процесс ?

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

> А не подскажете, как эти средства синхронизации называются?

В толксах вон какраз семафоры обсуждают =).

Deleted
()

>Если да, то каким-либо образом соединяется с уже запущенной копией, передает ей параметры командной строки и завершает работу.

А почему сразу не попытаться это сделать и в случае облома не осознать себя то единственной и вездесущей? Правда тоже не атомарно.. :/

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

> Встречный вопрос - как реализовать чтобы получить race condition ?

Точно так, как ты описал.

> или ты думаешь что ядро при создании процесса бросит свое дело на полпути и побежит создавать другой процесс ?


Ядро будет создавать и убивать процессы, пока ты сканируешь /proc.

Самая больша проблема в твоём варианте - это то, что непонятно что именно следует делать сначала: сканировать на наличие таких же процессов или организовывать средства IPC (для передачи параметров).

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

>Ядро будет создавать и убивать процессы, пока ты сканируешь /proc.

Подумай о том что сказал - что будет создано после тебя мало интересно, твой пид уже есть в системе и те процессы что запущены после тебя увидят твой пид и мирно свалят в сторонку, даже если каким то образом получат управление раньше тебя.

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

> rename в пределах одной файловой системы атомарен -- то есть нужно сперва создать файл со случайным именем в той же директории, и сделать rename/mv. Если rename обломился, то лок уже создан другим.
Но проблему с kill -9 это не решает.

> Может лучше просканировать /proc/PID/cmdline на наличие одноименных процессов ?

А если у пользователя установлено несколько версий программ - одна в /usr/bin/, а другая в ~/bin/. В таком случае по полному пути к бинарику искать нельзя. Поиск по имени бинарика имеет слишком большую погрешность - с таким именем вполне может быть запущен какой-нибудь скрипт.

> В толксах вон какраз семафоры обсуждают =).

Честно говоря, не очень хотелось бы их использовать, т. к. они имеют время жизни ядра. На мой взгляд, десктопные приложения там сорить не должны (опять-таки про kill -9). Или это все глупые предубеждения? К тому же в таком случае не понятно, как разрешать проблему с доступом. Вот, к примеру, у меня есть приложение APP. При его запуске оно создает семафор ~/.APP. Но в таком случае пользователь hacker вполне может создать семафор /home/vasya/.APP и заблокировать его, в результате чего пользователь vasya не сможет запустить свое приложение.

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

>с таким именем вполне может быть запущен какой-нибудь скрипт.

А если у пользователя есть скрипт который создает lockfile с таким же именем ? Короче - еслибы у бабушки был член - она была бы дедушкой :)

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

> Подумай о том что сказал - что будет создано после тебя мало интересно, твой пид уже есть в системе и те процессы что запущены после тебя увидят твой пид и мирно свалят в сторонку, даже если каким то образом получат управление раньше тебя.

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

Если считаешь, что такой "одновременный" запуск процессов невозможен, попробуй запустить такой примерчик:

#include <unistd.h>

int main()
{
if (fork())
wait(NULL);
else
sleep(100);
return 0;
}

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

Какое это отношение имеет к делу ? Ты хочешь сказать что при выполении getpid текущим процессом в системе может существовать процесс пид которого меньше чем у текущего но он еще не зарегистрирован ? Приведи пример такого кода.

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

> Какое это отношение имеет к делу ? Ты хочешь сказать что при выполении getpid текущим процессом в системе может существовать процесс пид которого меньше чем у текущего но он еще не зарегистрирован ? Приведи пример такого кода.

PID процесса, созданного позже, может быть меньше.

Deleted
()

Стандарнтый пример с установкой блокировки файла приведен в книге Стивенса "Unix: взаимодействие процессов". Общая идея такая: Демон пытается создать файл. Если ему это удается -- значит он первая запущенная копия, он ставит блокировку flock и записывает в файл свой PID. Если файл уже существует, демон пытается получить блокировку, если ему это не удается, значит существует исполняеющаяся копия демона. В это случае новая копия выводит что-то вроде "Already running..." и завершается. Если получить блокировку все-таки удается, значит предыдущая копия была убита и ядро автоматически сняло блокировку. В этом случае новая копия продолжает работу с сообщением "Subsystem is blocked, but deamon is dead".

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

Пожалуй мой вариант плох. Если система работает достаточно долго то пиды могут начать раздаваться по второму кругу..

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

>PID процесса, созданного позже, может быть меньше.
Кстати - хоть мой вариант и плох это утверждение неверно. Большему пиду всегда соотвествует процесс который запущен позже, кроме естественно того случая когда пиды начинают раздаваться по второму кругу.

kerosinkin
()

open(O_RDWR);
L1: fcntl(F_SETLK);
if (обломилось) {
  fcntl(F_GETLK); // узнаём pid работающей проги
  открываем другой файл, идентифицируемый нашим PID'ом,
  пишем туда argv, закрываем;
  L2: kill(pid, SIGUSR1);
} else {
  sigaction(SIGUSR1);
  работаем;
}

Между L1 и L2 есть race condition. Хотя гарантируется, что
два процесса не займут один lock-файл, но может получиться,
что пока второй процесс ползёт от L1 до L2, первый может завершиться.
Против этого можно всю церемонию завернуть в цикл, условием
продолжения которого будет неудачный kill.

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

> Большему пиду всегда соотвествует процесс который запущен позже, кроме естественно того случая когда пиды начинают раздаваться по второму кругу.

пиды могут раздаваться вообще случайно

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

В нормальном состоянии - нет. После превышения лимита на количество пидов - заход на второй круг - может быть и такое.

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

+1

в качестве лок-файла можно еще создавать линк на какой-нибудь уже существующий файл

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

> В нормальном состоянии - нет.

С какого потолка снял? В большинстве случаев так, да. Но полагаться на это нельзя.

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

> rename в пределах одной файловой системы атомарен

Атомарность атомарности рознь :)

> Если rename обломился, то лок уже создан другим.

А он не обломится, он просто удалит старый лок и положит на его место новый.

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

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

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

> Блин вот вы странные

Это вы странные. Есть стандарт, который говорит лишь, что все пиды разные. Конкретное числовое значение никакого смысла не несёт.

> учесть всех тараканов полюбому не получится.

Вот именно. Даже и пытаться не надо. Читаем стандарт и делаем по нему. Благо, это не тот случай, когда стандарт расходится с реальностью, что, к сожалению, тоже случается.

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

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

Бывает стандартизованное поведение и не стандартизованное. Поведение того же open стандартизовано и никакие патчи это поведение менять не должны (иначе - ССЗБ). PID'ы же могут выдаваться хоть по какой логике, никакого "правильного" поведения нигде не описано, а следовательно и полагаться на это не стоит.

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

>Есть стандарт, который говорит лишь, что все пиды разные. Какой стандарт ? Государственный ? Если речь о POSIX то о /proc можно вообще тогда не заикаться.

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

Что именно ? Надо было тогда сразу сказать что нужен посикс и не разводить сопли про пиды, поведение которых вполне определено в LINUX.

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

> не разводить сопли про пиды, поведение которых вполне определено в LINUX

Кто сказал про Linux? За всех не буду говорить, но лично я про /proc ни слова не сказал. Ну и опять же, даже в Linux бывает другое поведение и это не есть нарушение каких-то вековых устоев.

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

> Надо было тогда сразу сказать что нужен посикс и не разводить сопли про пиды, поведение которых вполне определено в LINUX.

И где же оно определено в Linux? Единственное что определно - это неодинаковость pid'ов у разных процессов. Остальное разработчики могут запросто изменить в будущих релизах.

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

Кстати вот:

[2009.04.05 04:28:43] ivan@ivan-laptop ~
$ stat /proc/8201
  File: `/proc/8201'
  Size: 0         	Blocks: 0          IO Block: 1024   Каталог
Device: 3h/3d	Inode: 507228      Links: 7
Access: (0555/dr-xr-xr-x)  Uid: ( 1000/    ivan)   Gid: ( 1000/    ivan)
Access: 2009-04-05 04:26:59.966425599 +0600
Modify: 2009-04-05 04:26:59.966425599 +0600
Change: 2009-04-05 04:26:59.966425599 +0600

[2009.04.05 04:29:18] ivan@ivan-laptop ~
$ stat /proc/15004
  File: `/proc/15004'
  Size: 0         	Blocks: 0          IO Block: 1024   Каталог
Device: 3h/3d	Inode: 400432      Links: 7
Access: (0555/dr-xr-xr-x)  Uid: ( 1000/    ivan)   Gid: ( 1000/    ivan)
Access: 2009-04-04 22:48:50.137195717 +0600
Modify: 2009-04-04 22:48:50.137195717 +0600
Change: 2009-04-04 22:48:50.137195717 +0600

Как видно, процесс с меньшим PIDом появился позже. Ядро ванильное, 2.6.29.

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

Касательно стандартов о которых так много тут говорят большевики - первый же вопрос: где вы собираетесь создавать lockfile ? В домашней директории пользователя ? - другой пользователь преспокойно запустит вторую копию программы ничего не зная о нем; в /tmp ? - может существовать программа другого разработчика и стандарт ему не запрещает создать одноименный lockfile и ваша програма вообще никогда не запустится. Так что тараканов на всех хватит :)

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

1 Смущает 15004 на laptop, у меня максимальный pid на даннй момент 1700, аптайм порядка 6 часов (по умолчанию 32768) так что вполне мог зайти на второй круг.
2 У котого сеть не заработала на 2.6.29 ванильном - им сейчас стоит сделать вывод что linux не гарантирует работу сети ?

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

Да, пожалуй, flock - наиболее адекватное решение. Единственное, хотелось бы отметить - при этом необходимо создавать lock файл с правами 600, т. к. flock может заблокировать файл, даже если пользователь имеет только права на чтение.

riYu
() автор топика

libunique не подойдёт?

Zenom ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.