Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Zakleszczenia na plikach -nie można przerwać działania skryptu
Forum PHP.pl > Forum > PHP
kreska
Witam
Mam obawy, że moje skrypty operujące na plikach mogą się zakleszczać powodując awarie na serwerze. Po zakleszczeniu konieczny jest restart serwera! Dobrze byłoby, gdyby ewentualne zakleszczenia usuwały się same po upływie określonego czasu np. 30 sekund.
Funkcja set_time_limit () nie spełnia w tym przypadku swojego zadania, bo nie potrafi zakończyć działania skryptu, który nałożył na plik blokadę.

Prosty przykład. Są dwa skrypty, które nakładają blokady do zapisu na dwa pliki.
Skrypt1

CODE

set_time_limit(35);

echo '<br>START 1';
$plik = fopen("test_1", "w");

flock($plik, 2);
sleep(30); //opoznienie dzialania -czekaj 30 sek na otwarcie skryptu 2

$plik2 = fopen("test_2", "w");

flock($plik2, 2);
echo '<br>KONIEC 1';




Skrypt2
CODE

set_time_limit(2);

echo '<br>START 2';
$plik2 = fopen("test_2", "w");
flock($plik2, 2);

$plik = fopen("test_1", "w");
flock($plik, 2);

echo '<br>KONIEC 2';



Skrypt1 należy uruchomić pierwszy, a następnie w ciągu 30 sekund w (drugim oknie przeglądarki) Skrypt2. Oba skrypty będą działać w nieskończoność i zablokują dostęp do plików na zawsze, pomimo tego, że zostaną zamknięte okna przeglądarki. Nawet zarejestrowanie funkcji porządkującej za pomocą register_shutdown_function, która odblokuje pliki nic nie pomoże, ponieważ skrypty nie są przerwane przez upłynięcie dozwolonego czasu ustawionego za pomocą set_time_limit.

Zakleszczenie wynikło z tego, że skrypt2 czeka aż skrypt1 zwolni blokadę na plik test_1, a skrypt1 czeka na zwolnienie blokady na plik test_2

Wiem jak unikać zakleszczeń, ale przy większym projekcie, czasem może się coś przeoczyć, dlatego interesuje mnie, czy jest możliwość bezwzględnego, absolutnego, zakończenia skryptu i zwolnienie zasobów po upływie określonego czasu, czy istnieje coś co można ustawić w konfiguracji serwera, albo jakaś funkcja w php?

Pozdrawiam i czekam na odpowiedzi
phpion
Nie widzę abyś gdziekolwiek zwalniał blokadę poprzez flock($file, LOCK_UN) lub flock($file, 3). Ponadto nie zamykasz plików. Ogólnie rzecz biorąc operacje na dużych plikach (a te pewnie takie są skoro tak długo schodzi operowanie na nich) są bardzo ryzykowne. Dla dużych zbiorów danych zdecydowanie lepiej nadają bazy danych. W plikach powinno się przetrzymywać raczej niewielkie porcje danych lub np. dane z cache. Nie dziw się więc, że jeżeli nakładasz blokadę na plik, trzymasz ją przez 30 sekund i w tym momencie odpalasz inny skrypt próbujący korzystać z tych samych zasobów, rezultat jest taki jaki opisałeś. Możesz przecież (zakładam) pobrać dane z pliku, zapisać je do tablicy, zwolnić blokadę i operować na danych zapisanych w tablicy.
kreska
Cytat(phpion @ 20.01.2009, 17:27:35 ) *
<br />Nie widzę abyś gdziekolwiek zwalniał blokadę poprzez flock($file, LOCK_UN) lub flock($file, 3). Ponadto nie zamykasz plików...<br />
<br /><br /><br />
To był tylko przykład. Oczywiście w praktyce zwalniam blokady, a pliki zwykle są małe. Tylko dla przejrzystości w przykładzie pominąłem zwalnianie blokady. Z tego co wiem, to blokady są automatycznie i tak zwalniane po zakończeniu działania skryptu i nawet nie musiałbym ich zwalniać tak wyczytałem gdzieś i są to informacje raczej pewne. A problem tkwi w tym, że jest zakleszczenie i skrypt nigdy się nie zakończy! Skrypt stoi w miejscu blokady i serwer nie kończy jego działania nawet po upływie czasu.

Jak więc zwolnić zasoby? Pozostaje tylko restart serwera?
ucho
Według manuala masz racje - na zakończenie działa skryptu wszystkie pliki są zamykane a blokady zdejmowane. Ale to co robisz jest po prostu niepoprawne - jeśli są dwa procesy korzystające z tych samych zasobów to powinny blokować pliki w tej samej kolejności - np. najpierw test1, potem test2 - tylko i wyłącznie wtedy nie ma groźby zakleszczenia.
Jeśli naprawdę nie możesz tego zmienić użyj kombinacji nieblokującego flock() i sleep() (tylko unixy)- będziesz mógł zareagować jeśli skrypt zbyt długo czeka na dane a i sam php będzie prawdopodobnie już egzekwować limit czasu, skoro nie będzie wisiał na systemowej funkcji od blokowania plików.
kreska
Cytat(ucho @ 20.01.2009, 17:59:53 ) *
<br /> Ale to co robisz jest po prostu niepoprawne - jeśli są dwa procesy korzystające z tych samych zasobów to powinny blokować pliki w tej samej kolejności - np. najpierw test1, potem test2 - tylko i wyłącznie wtedy nie ma groźby zakleszczenia<br />


Dzięki :-)
To był tylko przykład, wiem jak unikać zakleszczeń :-)
ucho mówisz dobrze, też tak myślałem. Zarówno o kolejności blokowania, że zawsze powinna być taka sama jak i o nieblokującym flock. Nigdy nie używałem nieblokującego flock, chyba trzeba użyć flock($plik, 4) i w pętli sprawdzać czy można nałożyć blokadę, coś w stylu:
while (!flock($plik, 4))
{
sleep(1);
}

Ale mnie po prostu chodziło oto, że czasem można coś przeoczyć i wtedy nastąpi poważny problem, bo serwer nie będzie mógł zakończyć działania skryptów. Więc dobrze byłoby, gdyby można było coś ustawić w konfiguracji, że jeśli skrypty się zakleszczyły, to po czasie zostaną zakończone, a zasoby, które zarezerwowały zostaną zwolnione. W dużym projekcie przecież łatwo o pomyłki.
Dzięki za odpowiedzi. Widać, że ucho się zna!
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.