Dapatkah saya mengeksekusi free () atau close () di penangan sinyal? [duplikat]
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+C
interupsi untuk menjalankan signal_handler
fungsi satu kali alih-alih langsung menghentikan proses. Saya membaca bahwa beberapa fungsi seperti mungkin free
tidak aman asinkron dan TIDAK akan dijalankan di signal_handler
tetapi saya tidak yakin tentang itu.
Dapatkah saya menjalankan fungsi seperti free
, close
, exit
atau bahkan pthread_join
dalam penangan sinyal?
Jawaban
Tidak. Hanya fungsi yang terdaftar di man 7 keamanan sinyal yang aman untuk dipanggil di dalam penangan sinyal.
close
terdaftar dan harus aman. free
tidak. Untuk alasan mengapa Anda harus melihat kode sumbernya (mengandung kunci). exit
tidak aman karena dapat memanggil penangan pembersihan sewenang-wenang. Anda memiliki _exit
yang keluar secara tiba-tiba tanpa pembersihan.
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.
Jawaban singkatnya tidak:
7.1.4 Penggunaan fungsi perpustakaanC 2011 Draf Online
...
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
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 stderr
dipetakan 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.
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) .