Program wykonuje setki(w zasadzie to grupowo robi 10000) operacji zapisu plików do określonego folderu z wątków rayona(rust) i wygląda na to, że bez względu czy ubijam go sygnałem TERM czy KILL, to nieco później (0-10s) po zabiciu programu, nie mogę usunąć całego folderu z plikami, bo wygląda, że program ciągle w tle tworzy nowe pliki, więc próba usunięcia takiego katalogu przez "rm -rf" wypisuje błąd "rm: cannot remove '/opt/tmp_folder/short_normal_1/16474004021118382402': Directory not empty"
Zatem by rozwiązać problem przerzucam timer końca działania do programu zamiast ubijać program z zewnątrz.
Jednak mam tutaj ponownie zagwozdkę.
Mam dwie koncepcje
Pierwsza to taka, że pierwszy wątek który złapie problem, to przerywa cały program:
fn check_for_exit() {
if time_left < 0 {
process::exit(127);
}
}
files_chunks.into_par_iter().for_each(|| {
check_for_exit();
for file in files_chunks {
fs::copy("file", output_dir);
}
});
Druga to taka, że czekam aż wszystkie wątki się skończą i dopiero wtedy przerywam wykonywanie programu
fn check_for_exit() -> bool {
return time_left < 0;
}
files_chunks.into_par_iter().map(|| {
if check_for_exit() {
return None;
}
for file in files_chunks {
fs::copy("file", output_dir);
}
Some(())
}).while_some().collect<()>();
if check_for_exit() {
process::exit(127);
}
Niby punkt drugi bezpieczniejszy, ale punkt pierwszy też przecież przecież powinien wszystkie wątki z kopiowaniem plików ubić. Dobrze kminię, czy jednak punkt pierwszy nie jest bezpieczny?
#programowanie
#rustlang
@qarmin Nie pisałem dawno w rust, zwłaszcza na tym poziomie, ale zdecydowanie druga opcja. Wydaje mi się, że w pierwszej opcji będziesz miał proces w kolejce do ubicia/ubity, a to co zostanie to będą tzw. detached threads. Ale nie jestem (już) ekspertem, podpytaj może kogoś innego
@qarmin a to nie jest kwestia tego, że operacje na plikach robi kernel? Ubicie procesu nie przerywa fs::copy.
Po drugie, obsługa sygnałów nie jest synchroniczna. Jak zrobisz kill PID && rm costam, to na pewno to nie zadziała. Musisz poczekać, aż proces obsłuży sygnał i się zamknie.
Jak robisz timeout na wątkach wewnątrz programu, to z pewnością da się to bardziej elegancko obsłużyć.
@qarmin Analizując obie koncepcje, które przedstawiłeś, można zauważyć kilka istotnych różnic w sposobie zarządzania zakończeniem wątków i zatrzymaniem programu.
Pierwsza koncepcja
-
Zalety:
-
Każdy wątek sprawdza warunek time_left < 0 przed rozpoczęciem kopiowania.
-
Jeśli warunek jest spełniony, natychmiast wywołuje process::exit(127), co natychmiastowo kończy cały program.
-
Wady:
-
process::exit(127) powoduje natychmiastowe zakończenie programu bez czekania na zakończenie pozostałych wątków. To może skutkować niekompletnym zakończeniem operacji IO, co może być przyczyną problemów z plikami.
-
Możliwe nieprzewidywalne zachowanie, jeśli process::exit(127) jest wywoływane z wielu wątków jednocześnie.
Druga koncepcja
-
Zalety:
-
Sprawdza warunek time_left < 0 przed rozpoczęciem kopiowania w każdym wątku, ale zamiast natychmiastowego zakończenia, wątki, które spełniają warunek, po prostu kończą swoją pracę.
-
Pozwala wszystkim aktywnym wątkom dokończyć swoje operacje kopiowania, zanim program sprawdzi, czy powinien zakończyć się process::exit(127).
-
Bezpieczniejsze podejście, ponieważ nie powoduje natychmiastowego zakończenia programu, co pozwala na bardziej przewidywalne zarządzanie zasobami.
-
Wady:
-
Może powodować krótkie opóźnienie w zakończeniu programu, jeśli trzeba czekać na zakończenie wszystkich wątków.
Wnioski
Druga koncepcja jest bardziej bezpieczna i elegancka, ponieważ pozwala na kontrolowane zakończenie programu i uniknięcie problemów związanych z nieskończonym tworzeniem plików po wywołaniu timeout.
Natychmiastowe zakończenie programu przy użyciu process::exit w pierwszej koncepcji może prowadzić do nieprzewidywalnych problemów związanych z niedokończonymi operacjami IO. W drugiej koncepcji wątki mogą bezpiecznie zakończyć swoje zadania, co zmniejsza ryzyko wystąpienia problemów z plikami i zasobami.
Zatem rekomenduję skorzystanie z drugiej koncepcji. Jeśli jednak decydujesz się na pierwszą koncepcję, warto wprowadzić mechanizm, który upewni się, że wszystkie wątki zakończyły swoją pracę przed zamknięciem programu, aby uniknąć problemów z niekompletnym przetwarzaniem plików.
Zaloguj się aby komentować