Gunakan sigaction()
kecuali Anda punya alasan yang sangat kuat untuk tidak melakukannya.
The signal()
antarmuka memiliki kuno (dan karenanya ketersediaan) dalam mendukung, dan didefinisikan dalam standar C. Namun demikian, ia memiliki sejumlah karakteristik yang tidak diinginkan yang sigaction()
menghindari - kecuali jika Anda menggunakan bendera yang ditambahkan secara eksplisit sigaction()
untuk memungkinkannya mensimulasikan signal()
perilaku lama dengan setia .
- The
signal()
Fungsi tidak (selalu) memblokir sinyal lainnya dari tiba sementara penangan saat mengeksekusi; sigaction()
dapat memblokir sinyal lain sampai handler saat ini kembali.
- The
signal()
fungsi (biasanya) me-reset kembali aksi sinyal untuk SIG_DFL
(default) untuk hampir semua sinyal. Ini berarti signal()
pawang harus menginstal ulang dirinya sendiri sebagai tindakan pertama. Ini juga membuka jendela kerentanan antara waktu ketika sinyal terdeteksi dan pawang diinstal ulang di mana jika instance kedua sinyal tiba, perilaku default (biasanya berakhir, kadang-kadang dengan prasangka - alias dump inti) terjadi.
- Perilaku tepat
signal()
bervariasi di antara sistem - dan standar mengizinkan variasi tersebut.
Ini adalah alasan umumnya baik untuk menggunakan sigaction()
bukan signal()
. Namun, antarmuka sigaction()
tidak bisa disangkal lebih fiddly.
Mana saja dari kedua Anda gunakan, jangan tergoda oleh antarmuka sinyal alternatif seperti
sighold()
,
sigignore()
,
sigpause()
dan
sigrelse()
. Mereka secara nominal alternatif sigaction()
, tetapi mereka hanya nyaris tidak terstandarisasi dan hadir dalam POSIX untuk kompatibilitas mundur daripada untuk penggunaan serius. Perhatikan bahwa standar POSIX mengatakan perilaku mereka dalam program multi-utas tidak terdefinisi.
Program dan sinyal multi-utas adalah kisah rumit lainnya. AFAIK, keduanya signal()
dan sigaction()
OK di aplikasi multi-utas.
Cornstalks mengamati :
Halaman manual Linux untuk signal()
mengatakan:
Efek signal()
dalam proses multi-utas tidak ditentukan.
Jadi, saya pikir sigaction()
adalah satu-satunya yang dapat digunakan dengan aman dalam proses multi-threaded.
Itu menarik. Halaman manual Linux lebih membatasi dari POSIX dalam hal ini. POSIX menentukan untuk signal()
:
Jika prosesnya multi-threaded, atau jika prosesnya single-threaded dan penangan sinyal dieksekusi selain sebagai hasil dari:
- Proses pemanggilan
abort()
, raise()
, kill()
, pthread_kill()
, atau sigqueue()
untuk menghasilkan sinyal yang tidak diblokir
- Sinyal yang tertunda diblokir dan dikirim sebelum panggilan yang tidak diblokir kembali
perilaku tidak terdefinisi jika penangan sinyal merujuk ke objek apa pun selain errno
dengan durasi penyimpanan statis selain dengan menetapkan nilai ke objek yang dinyatakan volatile sig_atomic_t
, atau jika penangan sinyal memanggil fungsi yang didefinisikan dalam standar ini selain dari salah satu fungsi yang tercantum dalam Konsep Sinyal .
Jadi POSIX dengan jelas menentukan perilaku signal()
dalam aplikasi multi-utas.
Namun demikian, sigaction()
pada dasarnya akan lebih disukai dalam semua keadaan - dan kode multi-ulir portabel harus digunakan sigaction()
kecuali ada alasan kuat mengapa tidak dapat (seperti "hanya menggunakan fungsi yang didefinisikan oleh Standar C" - dan ya, kode C11 dapat multi -baca). Yang pada dasarnya adalah apa yang paragraf pembuka dari jawaban ini juga mengatakan.
signal
ini sebenarnya dari perilaku Unix System V. POSIX memungkinkan perilaku ini atau perilaku BSD yang lebih waras, tetapi karena Anda tidak bisa memastikan mana yang akan Anda dapatkan, masih lebih baik digunakansigaction
.SA_RESETHAND
, jugaSA_NODEFER
.sigaction()
, maka pada dasarnya Anda wajib menggunakan spesifikasi Standar C untuksignal()
. Namun, itu memberi Anda satu set opsi yang sangat miskin untuk apa yang dapat Anda lakukan. Anda dapat: memodifikasi (cakupan file) variabel tipevolatile sig_atomic_t
; panggil salah satu fungsi 'keluar cepat' (_Exit()
,quick_exit()
) atauabort()
; panggilansignal()
dengan nomor sinyal saat ini sebagai argumen sinyal; kembali. Dan itu saja. Hal lain tidak dijamin portabel. Itu sangat ketat sehingga kebanyakan orang mengabaikan aturan itu - tetapi kode yang dihasilkannya cerdik.sigaction()
demo dari GCC sendiri: gnu.org/software/libc/manual/html_node/... ; dansignal()
demo yang sangat baik dari GCC sendiri: gnu.org/software/libc/manual/html_node/… . Perhatikan bahwa dalamsignal
demo mereka menghindari mengubah handler dari Abaikan (SIG_IGN
) jika itu memang sengaja diatur sebelumnya.Bagi saya, baris di bawah ini sudah cukup untuk memutuskan:
http://pubs.opengroup.org/onlinepubs/009695399/functions/signal.html#tag_03_690_07
Baik Anda memulai dari awal atau memodifikasi program lama, sigaction harus menjadi pilihan yang tepat.
sumber
Mereka adalah antarmuka yang berbeda untuk fasilitas sinyal OS. Seseorang harus lebih suka menggunakan sigaction untuk memberi sinyal jika memungkinkan karena sinyal () memiliki perilaku yang ditentukan-implementasinya (seringkali cenderung rentan) dan berperilaku berbeda pada Windows, OS X, Linux dan sistem UNIX lainnya.
Lihat catatan keamanan ini untuk detailnya.
sumber
sinyal () adalah standar C, sigaction () tidak.
Jika Anda dapat menggunakan keduanya (yaitu, Anda menggunakan sistem POSIX), maka gunakan sigaction (); tidak ditentukan apakah sinyal () me-reset handler, artinya agar portabel Anda harus memanggil sinyal () lagi di dalam handler. Yang lebih buruk adalah ada perlombaan: jika Anda mendapatkan dua sinyal secara berurutan, dan yang kedua dikirim sebelum Anda menginstal ulang pawang, Anda akan memiliki tindakan default, yang mungkin akan mematikan proses Anda. sigaction () , di sisi lain, dijamin menggunakan semantik sinyal "andal". Anda tidak perlu menginstal ulang handler, karena itu tidak akan pernah diatur ulang. Dengan SA_RESTART, Anda juga bisa mendapatkan beberapa panggilan sistem untuk memulai ulang secara otomatis (jadi Anda tidak perlu memeriksa EINTR secara manual). sigaction () memiliki lebih banyak opsi dan dapat diandalkan, sehingga penggunaannya dianjurkan.
Psst ... jangan beri tahu siapa pun yang saya katakan ini, tetapi POSIX saat ini memiliki fungsi bsd_signal () yang bertindak seperti sinyal () tetapi memberikan semantik BSD, yang berarti dapat diandalkan. Penggunaan utamanya adalah untuk porting aplikasi lama yang dianggap sinyal yang dapat diandalkan, dan POSIX tidak merekomendasikan menggunakannya.
sumber
bsd_signal()
- beberapa implementasi POSIX mungkin memiliki fungsi, tetapi POSIX sendiri tidak mengandung fungsi seperti itu (lihat POSIX ).Pendeknya:
sigaction()
baik dan terdefinisi dengan baik, tetapi merupakan fungsi Linux dan hanya berfungsi di Linux.signal()
buruk dan kurang didefinisikan, tetapi merupakan fungsi standar C dan berfungsi pada apa pun.Apa yang dikatakan halaman manual Linux tentang hal itu?
man 2 signal
(lihat online di sini ) menyatakan:Dengan kata lain: jangan gunakan
signal()
. Gunakansigaction()
sebagai gantinya!Apa yang dipikirkan GCC?
Sumber: https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-Handling
Jadi, jika Linux dan GCC mengatakan untuk tidak menggunakan
signal()
, tetapi untuk menggunakansigaction()
, itu menimbulkan pertanyaan: bagaimana kita menggunakan hal yang membingungkan inisigaction()
!?Contoh Penggunaan:
Baca
signal()
contoh EXCELLENT GCC di sini: https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-HandlingDan
sigaction()
contoh EXCELLENT mereka di sini: https://www.gnu.org/software/libc/manual/html_node/Sigaction-Function-Example.htmlSetelah membaca halaman-halaman itu, saya menemukan teknik berikut untuk
sigaction()
:1.
sigaction()
, karena ini adalah cara yang tepat untuk memasang penangan sinyal, seperti dijelaskan di atas:2. Dan untuk
signal()
, meskipun itu bukan cara yang baik untuk memasang penangan sinyal, seperti dijelaskan di atas, masih baik untuk mengetahui cara menggunakannya.Inilah kode demonstrasi GCC yang disalin, karena hampir sebagus yang akan didapat:
Tautan utama yang harus diperhatikan:
signal()
contoh penggunaan GCC resmi : https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-Handlingsigaction()
Contoh penggunaan GCC resmi : https://www.gnu.org/software/libc/manual/html_node/Sigaction-Function-Example.htmlsigemptyset()
dansigfillset()
; Saya masih tidak mengerti persis ini, tetapi tahu itu penting: https://www.gnu.org/software/libc/manual/html_node/Signal-Sets.htmlLihat juga:
sumber
Dari
signal(3)
halaman manual:Keduanya memohon fasilitas dasar yang sama. Anda mungkin seharusnya tidak memanipulasi respons sinyal tunggal dengan keduanya, tetapi mencampurkannya seharusnya tidak menyebabkan apa pun rusak ...
sumber
Saya juga menyarankan menggunakan sigaction () di atas sinyal () dan ingin menambahkan satu titik lagi. sigaction () memberi Anda lebih banyak opsi seperti pid dari proses yang mati (mungkin menggunakan struct siginfo_t).
sumber
Saya akan menggunakan sinyal () karena lebih portabel, secara teori setidaknya. Saya akan memilih komentator mana pun yang dapat membuat sistem modern yang tidak memiliki lapisan kompatibilitas POSIX dan mendukung sinyal ().
Mengutip dari dokumentasi GLIBC :
sumber
Dari sinyal halaman manual (7)
Dan saya akan mengatakan "masalah" ini ada untuk sinyal (2) dan sigaction (2) . Jadi berhati-hatilah dengan sinyal dan pthreads.
... dan sinyal (2) tampaknya memanggil sigaction (2) di bawahnya di Linux dengan glibc.
sumber