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 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.