Существуют разные подходы. Обычно используется файл, в котором пишется PID процесса, но это «внутренняя» блокировка, программа сама себя блокирует, зная свой PID. Но существуют и другие подходы для внешней блокировки вызываемой программы, если программа сама не умеет блокироваться.
lockfile
Типовое использование:
#!/bin/bash
lockfile -r 0 /tmp/the.lock || exit 1
# Что-то тут делаем, что надо сделать
rm -f /tmp/the.lock
Сразу возникает вопрос что будет, если скрипт перед удалением файла прервётся, например сервер выключится.
flock
flock /tmp/lalala find /
Тот же вопрос — что если работа flock прервётся.
Solo
solo не имеет этого недостатка (зато имеет другие, естественно).
timkay.com/solo/ — скрипт на Perl, блокирующий параллельный запуск программы. Для блокировки используется открытие указанного TCP порта на 127.0.0.1 . Переделанная версия ещё и ждёт -wait секунд для повторных попыток запустить программу:
#!/usr/bin/perl -s --
#
# solo v1.7
# Prevents multiple cron instances from running simultaneously.
#
# Copyright 2007-2016 Timothy Kay
# http://timkay.com/solo/
#
# It is free software; you can redistribute it and/or modify it under the terms of either:
#
# a) the GNU General Public License as published by the Free Software Foundation;
# either version 1 (http://dev.perl.org/licenses/gpl1.html), or (at your option)
# any later version (http://www.fsf.org/licenses/licenses.html#GNUGPL), or
#
# b) the "Artistic License" (http://dev.perl.org/licenses/artistic.html), or
#
# c) the MIT License (http://opensource.org/licenses/MIT)
#
use Socket;
alarm $timeout if $timeout;
$port =~ /^\d+$/ or $noport or die "Usage: $0 -port=PORT [-wait=120] COM
$wait =~ /^\d+$/ or $nowait ;
$wait = 1 unless $wait;
if ($port)
{
# To work with OpenBSD: change to
# $addr = pack(CnC, 127, 0, 1);
# but make sure to use different ports across different users.
# (Thanks to www.gotati.com .)
$addr = pack(CnC, 127, $<, 1);
print "solo: bind ", join(".", unpack(C4, $addr)), ":$port\n" if $verbose;
$^F = 10; # unset close-on-exec
$|=1;
my $ok;
foreach my $t(1..$wait){
eval {
socket(SOLO, PF_INET, SOCK_STREAM, getprotobyname('tcp')) or die "socket: $!";
bind(SOLO, sockaddr_in($port, $addr)) or $silent? exit: die "solo($port):
$ok=1;
};
last if $ok;
die("Timeout") if $t == $wait;
if($@){
print STDERR '.';
sleep 1;
}
}
}
sleep $sleep if $sleep;
exec @ARGV;
Leave a Reply
You must be logged in to post a comment.