Czy mogę wykonać free () lub close () w module obsługi sygnału? [duplikować]
Mam kod, który wygląda następująco:
//global variables
void signal_handler() {
//deallocation of global variables
free(foo);
close(foo_2);
exit(0);
}
int main () {
signal(SIGINT, signal_handler);
//irrelevant code
}
Jak widać, zmieniłem CTRL+C
przerwanie, aby wykonać signal_handler
funkcję raz, zamiast natychmiast zabijać proces. Czytałem gdzieś, że niektóre funkcje, takie jak mogą być, free
nie są bezpieczne dla asynchronii i NIE będą wykonywane w programie, signal_handler
ale nie jestem tego pewien.
Mogę wykonywać funkcje takie jak free
, close
, exit
lub nawet pthread_join
w obsługę sygnału?
Odpowiedzi
Nie. Tylko funkcje wymienione w man 7 bezpieczeństwo sygnału są bezpieczne do wywołania wewnątrz modułu obsługi sygnału.
close
jest wymieniony i powinien być bezpieczny. free
nie jest. Z powodów, dla których musiałbyś spojrzeć na jego kod źródłowy (zawiera blokady). exit
nie jest bezpieczny, ponieważ może wywoływać dowolne programy obsługi czyszczenia. Masz, _exit
który wychodzi nagle bez czyszczenia.
Z technicznego punktu widzenia możesz skompilować program, który wywołuje takie funkcje w programie obsługi sygnału, nic Cię przed tym nie powstrzyma. Jednak spowoduje to niezdefiniowane zachowanie, jeśli funkcja, którą próbujesz wykonać, nie jest bezpieczna dla sygnału asynchronicznego. To nie jest tak, że niebezpieczne funkcje po prostu „NIE wykonałyby się”, jak mówisz, bardzo dobrze mogłyby, ale nadal byłoby to niezdefiniowane zachowanie.
Lista funkcji bezpiecznych dla sygnału asynchronicznego jest udokumentowana w man 7 signal-safety. close()
Funkcja jest bezpieczne, podczas gdy free()
i phtread_join()
nie są. exit()
Funkcją jest również nie bezpieczne połączenie z obsługi sygnału, jeśli chcesz wyjść z takim kontekście trzeba będzie to zrobić używając _exit()zamiast.
Jedynym sposobem na bezpieczne wywołanie funkcji, która nie jest bezpieczna dla sygnału asynchronicznego podczas odbierania sygnału, jest „zapamiętanie”, że musisz ją wywołać (na przykład ustawienie zmiennej globalnej), a następnie zrobić to po powrocie z programu obsługi sygnału.
Krótka odpowiedź brzmi: nie:
7.1.4 Korzystanie z funkcji bibliotecznychC 2011 Online Draft
...
4 Funkcje w bibliotece standardowej nie są gwarantowane do ponownego wprowadzenia i mogą modyfikować obiekty ze statycznym lub wątkowym czasem trwania. 188)
188) Zatem program obsługi sygnału w zasadzie nie może wywoływać standardowych funkcji bibliotecznych
Prawdziwy przykład konsekwencji - pracowałem nad systemem, który komunikował się z bazą danych Access. Był program obsługi sygnału, który próbował napisać komunikat o błędzie do konsoli fprintf
, ale w jakiś sposób podczas procesu obsługi sygnału stderr
został zmapowany do pliku .mdb, który przechował bazę danych, nadpisując nagłówek i niszcząc bazę danych bez możliwości naprawy.
Szczerze mówiąc , w programie obsługi sygnału niewiele można zrobić poza ustawieniem flagi do sprawdzenia w innym miejscu.
Czy mogę wykonać free () lub close () w module obsługi sygnału?
Zdecydowanie nie powinieneś. Patrz signal (7) i signal-safety (7)
W praktyce może to działać tak, jak chcesz, przez ponad połowę czasu. IIRC, kompilator GCC działa tak, jak chcesz i zwykle działa.
Lepszym podejściem jest użycie metody write (2) do potoku (7) (z wnętrza programu obsługi sygnału) i od czasu do czasu sprawdzanie tego potoku (w głównym programie) za pomocą funkcji poll (2) lub podobnych rzeczy.
Lub możesz ustawić jakiś volatile sigatomic_t flag;
(być może powinien również _Atomic) w swoim programie obsługi sygnału i sprawdzić tę flagę w innym miejscu (w głównym programie, poza programami obsługi sygnału).
Qt wyjaśnia to lepiej niż mógłbym zrobić w kilka minut.
W systemie Linux zobacz także signalfd (2) i eventfd (2) .