Czy mogę wykonać free () lub close () w module obsługi sygnału? [duplikować]

Dec 10 2020

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+Cprzerwanie, aby wykonać signal_handlerfunkcję raz, zamiast natychmiast zabijać proces. Czytałem gdzieś, że niektóre funkcje, takie jak mogą być, freenie są bezpieczne dla asynchronii i NIE będą wykonywane w programie, signal_handlerale nie jestem tego pewien.

Mogę wykonywać funkcje takie jak free, close, exitlub nawet pthread_joinw obsługę sygnału?

Odpowiedzi

1 dratenik Dec 10 2020 at 15:46

Nie. Tylko funkcje wymienione w man 7 bezpieczeństwo sygnału są bezpieczne do wywołania wewnątrz modułu obsługi sygnału.

closejest wymieniony i powinien być bezpieczny. freenie jest. Z powodów, dla których musiałbyś spojrzeć na jego kod źródłowy (zawiera blokady). exitnie jest bezpieczny, ponieważ może wywoływać dowolne programy obsługi czyszczenia. Masz, _exitktóry wychodzi nagle bez czyszczenia.

1 MarcoBonelli Dec 10 2020 at 15:46

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.

1 JohnBode Dec 10 2020 at 16:30

Krótka odpowiedź brzmi: nie:

7.1.4 Korzystanie z funkcji bibliotecznych
...
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
C 2011 Online Draft

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

BasileStarynkevitch Dec 10 2020 at 16:24

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