Dapatkah saya mengeksekusi free () atau close () di penangan sinyal? [duplikat]

Dec 10 2020

Saya memiliki kode yang terlihat seperti ini:

//global variables

void signal_handler() {
    //deallocation of global variables
    free(foo);
    close(foo_2);
    exit(0);
}

int main () {
    signal(SIGINT, signal_handler);

    //irrelevant code
}

Seperti yang Anda lihat, saya mengubah CTRL+Cinterupsi untuk menjalankan signal_handlerfungsi satu kali alih-alih langsung menghentikan proses. Saya membaca bahwa beberapa fungsi seperti mungkin freetidak aman asinkron dan TIDAK akan dijalankan di signal_handlertetapi saya tidak yakin tentang itu.

Dapatkah saya menjalankan fungsi seperti free, close, exitatau bahkan pthread_joindalam penangan sinyal?

Jawaban

1 dratenik Dec 10 2020 at 15:46

Tidak. Hanya fungsi yang terdaftar di man 7 keamanan sinyal yang aman untuk dipanggil di dalam penangan sinyal.

closeterdaftar dan harus aman. freetidak. Untuk alasan mengapa Anda harus melihat kode sumbernya (mengandung kunci). exittidak aman karena dapat memanggil penangan pembersihan sewenang-wenang. Anda memiliki _exityang keluar secara tiba-tiba tanpa pembersihan.

1 MarcoBonelli Dec 10 2020 at 15:46

Anda secara teknis dapat mengkompilasi program yang memanggil fungsi-fungsi tersebut dalam penangan sinyal, tidak ada yang menghentikan Anda untuk melakukannya. Namun ini akan mengakibatkan perilaku tidak terdefinisi jika fungsi yang Anda coba jalankan tidak async-signal-safe. Ini tidak seperti fungsi yang tidak aman hanya akan "TIDAK dijalankan" seperti yang Anda katakan, mereka bisa melakukannya dengan sangat baik, tapi itu masih merupakan perilaku yang tidak ditentukan.

Daftar fungsi async-signal-safe didokumentasikan di man 7 signal-safety. The close()Fungsi aman, sementara free()dan phtread_join()tidak. The exit()Fungsi ini juga tidak aman untuk memanggil dari penangan sinyal, jika Anda ingin keluar dari konteks seperti Anda harus melakukannya dengan menggunakan _exit()gantinya.

Satu-satunya cara untuk memanggil fungsi dengan aman yang tidak async-signal-safe saat menerima sinyal adalah dengan "mengingat" bahwa Anda harus memanggilnya (misalnya menyetel variabel global) dan kemudian melakukannya setelah kembali dari penangan sinyal.

1 JohnBode Dec 10 2020 at 16:30

Jawaban singkatnya tidak:

7.1.4 Penggunaan fungsi perpustakaan
...
4 Fungsi di perpustakaan standar tidak dijamin reentrant dan dapat memodifikasi objek dengan durasi penyimpanan statis atau benang. 188)
188) Jadi, penangan sinyal tidak bisa, secara umum, memanggil fungsi perpustakaan standar
C 2011 Draf Online

Contoh dunia nyata dari konsekuensi - Saya bekerja pada sistem yang berkomunikasi dengan database Access. Ada penangan sinyal yang mencoba menulis pesan kesalahan ke konsol dengan fprintf, tetapi entah bagaimana selama proses penanganan sinyal stderrdipetakan ke file .mdb yang menyimpan database, menimpa header dan merusak database sehingga tidak bisa diperbaiki.

Sejujurnya tidak banyak yang dapat Anda lakukan di penangan sinyal selain mengatur bendera untuk diperiksa di tempat lain.

BasileStarynkevitch Dec 10 2020 at 16:24

Dapatkah saya mengeksekusi free () atau close () di penangan sinyal?

Anda seharusnya tidak melakukannya. Lihat sinyal (7) dan keamanan sinyal (7)

Dalam praktiknya, ini mungkin berhasil seperti yang Anda inginkan mungkin lebih dari separuh waktu. IIRC, kompilator GCC melakukan seperti yang Anda inginkan, dan biasanya berfungsi.

Pendekatan yang lebih baik adalah dengan menggunakan beberapa tulis (2) ke pipa (7) (dari dalam penangan sinyal Anda) dan dari waktu ke waktu periksa pipa itu (dalam program utama Anda) dengan polling (2) atau hal-hal terkait.

Atau Anda bisa mengatur beberapa volatile sigatomic_t flag;(mungkin harus juga _Atomic) di penangan sinyal Anda, dan memeriksa tanda itu di tempat lain (di program utama, di luar penangan sinyal).

Qt menjelaskan itu lebih baik daripada yang bisa saya lakukan dalam beberapa menit.

Di Linux, lihat juga signalfd (2) dan eventfd (2) .