Bagaimana cara menggunakan penangan sinyal dalam bahasa C?

How Use Signal Handlers C Language



Pada artikel ini kami akan menunjukkan cara menggunakan penangan sinyal di Linux menggunakan bahasa C. Tetapi pertama-tama kita akan membahas apa itu sinyal, bagaimana sinyal itu akan menghasilkan beberapa sinyal umum yang dapat Anda gunakan dalam program Anda dan kemudian kita akan melihat bagaimana berbagai sinyal dapat ditangani oleh suatu program saat program dijalankan. Jadi ayo mulai.

Sinyal

Sinyal adalah peristiwa yang dihasilkan untuk memberi tahu proses atau utas bahwa beberapa situasi penting telah tiba. Ketika sebuah proses atau thread telah menerima sinyal, proses atau thread akan menghentikan apa yang dilakukannya dan mengambil beberapa tindakan. Sinyal mungkin berguna untuk komunikasi antar proses.







Sinyal Standar

Sinyal didefinisikan dalam file header signal.h sebagai konstanta makro. Nama sinyal diawali dengan SIG dan diikuti dengan deskripsi singkat tentang sinyal tersebut. Jadi, setiap sinyal memiliki nilai numerik yang unik. Program Anda harus selalu menggunakan nama sinyal, bukan nomor sinyal. Alasannya adalah nomor sinyal dapat berbeda menurut sistem tetapi arti nama akan menjadi standar.



makro NSIG adalah jumlah total sinyal yang ditentukan. Nilai dari NSIG adalah satu lebih besar dari jumlah total sinyal yang ditentukan (Semua nomor sinyal dialokasikan secara berurutan).



Berikut ini adalah sinyal standar:





Nama Sinyal Keterangan
SIGHUP Tutup prosesnya. Sinyal SIGHUP digunakan untuk melaporkan pemutusan terminal pengguna, mungkin karena koneksi jarak jauh terputus atau terputus.
TANDA Mengganggu proses. Ketika pengguna mengetik karakter INTR (biasanya Ctrl + C) sinyal SIGINT dikirim.
SIGQUIT Keluar dari proses. Ketika pengguna mengetik karakter QUIT (biasanya Ctrl + ) sinyal SIGQUIT dikirim.
SEGEL Instruksi ilegal. Ketika upaya dilakukan untuk mengeksekusi instruksi sampah atau hak istimewa, sinyal SIGILL dihasilkan. Juga, SIGILL dapat dihasilkan ketika tumpukan meluap, atau ketika sistem mengalami kesulitan menjalankan penangan sinyal.
SIGTRAP Jejak perangkap. Sebuah instruksi breakpoint dan instruksi trap lainnya akan menghasilkan sinyal SIGTRAP. Debugger menggunakan sinyal ini.
SIGABRT Menggugurkan. Sinyal SIGABRT dihasilkan ketika fungsi abort() dipanggil. Sinyal ini menunjukkan kesalahan yang dideteksi oleh program itu sendiri dan dilaporkan oleh pemanggilan fungsi abort().
SIGFPE Pengecualian floating-point. Ketika kesalahan aritmatika fatal terjadi, sinyal SIGFPE dihasilkan.
SIGUSR1 dan SIGUSR2 Sinyal SIGUSR1 dan SIGUSR2 dapat digunakan sesuai keinginan. Hal ini berguna untuk menulis penangan sinyal untuk mereka dalam program yang menerima sinyal untuk komunikasi antar-proses yang sederhana.

Tindakan Default Sinyal

Setiap sinyal memiliki tindakan default, salah satu dari berikut ini:

Ketentuan: Proses akan berakhir.
Inti: Proses akan berhenti dan menghasilkan file dump inti.
tanda: Proses akan mengabaikan sinyal.
Berhenti: Proses akan berhenti.
Akun: Proses akan berlanjut dari dihentikan.



Tindakan default dapat diubah menggunakan fungsi handler. Tindakan default beberapa sinyal tidak dapat diubah. SIGKILL dan SIGABRT tindakan default sinyal tidak dapat diubah atau diabaikan.

Penanganan Sinyal

Jika suatu proses menerima sinyal, proses memiliki pilihan tindakan untuk jenis sinyal tersebut. Proses dapat mengabaikan sinyal, dapat menentukan fungsi handler, atau menerima tindakan default untuk jenis sinyal tersebut.

  • Jika tindakan yang ditentukan untuk sinyal diabaikan, maka sinyal segera dibuang.
  • Program dapat mendaftarkan fungsi handler menggunakan fungsi seperti: sinyal atau sigasi . Ini disebut handler menangkap sinyal.
  • Jika sinyal belum ditangani atau diabaikan, tindakan defaultnya terjadi.

Kami dapat menangani sinyal menggunakan sinyal atau sigasi fungsi. Di sini kita melihat bagaimana yang paling sederhana sinyal() fungsi yang digunakan untuk menangani sinyal.

ke dalamsinyal() (ke dalamtanda, ruang kosong (*fungsi)(ke dalam))

NS sinyal() akan memanggil fungsi berfungsi jika proses menerima sinyal tanda . NS sinyal() mengembalikan pointer ke fungsi fungsi jika berhasil atau mengembalikan kesalahan ke errno dan -1 sebaliknya.

NS fungsi pointer dapat memiliki tiga nilai:

  1. SIG_DFL : Ini adalah penunjuk ke fungsi default sistem SIG_DFL () , dinyatakan dalam H berkas kepala. Ini digunakan untuk mengambil tindakan default dari sinyal.
  2. SIG_IGN : Ini adalah penunjuk ke fungsi abaikan sistem SIG_IGN () , dideklarasikan dalam H berkas kepala.
  3. Penunjuk fungsi penangan yang ditentukan pengguna : Jenis fungsi handler yang ditentukan pengguna adalah batal(*)(int) , berarti tipe pengembalian batal dan satu argumen bertipe int.

Contoh Penangan Sinyal Dasar

#termasuk
#termasuk
#termasuk
ruang kosongsig_handler(ke dalamtanda){

//Tipe kembalian fungsi handler harus batal
printf (' Fungsi penangan di dalam ');
}

ke dalamutama(){
sinyal(TANDA,sig_handler); // Daftarkan penangan sinyal
untuk(ke dalamSaya=1;;Saya++){ //loop tak terbatas
printf ('%d : Di dalam fungsi utama ',Saya);
tidur(1); // Tunda selama 1 detik
}
kembali 0;
}

Pada tangkapan layar dari output Example1.c, kita dapat melihat bahwa pada fungsi utama infinite loop sedang dieksekusi. Saat pengguna mengetik Ctrl+C, eksekusi fungsi utama berhenti dan fungsi pengendali sinyal dipanggil. Setelah fungsi handler selesai, eksekusi fungsi utama dilanjutkan. Saat pengguna mengetik Ctrl+, prosesnya berhenti.

Abaikan Sinyal Contoh

#termasuk
#termasuk
#termasuk
ke dalamutama(){
sinyal(TANDA,SIG_IGN); // Daftarkan penangan sinyal untuk mengabaikan sinyal

untuk(ke dalamSaya=1;;Saya++){ //loop tak terbatas
printf ('%d : Di dalam fungsi utama ',Saya);
tidur(1); // Tunda selama 1 detik
}
kembali 0;
}

Di sini fungsi handler adalah mendaftar ke SIG_IGN () berfungsi untuk mengabaikan aksi sinyal. Jadi, ketika pengguna mengetik Ctrl + C, TANDA sinyal dihasilkan tetapi aksinya diabaikan.

Daftar Ulang Contoh Penangan Sinyal

#termasuk
#termasuk
#termasuk

ruang kosongsig_handler(ke dalamtanda){
printf (' Fungsi penangan di dalam ');
sinyal(TANDA,SIG_DFL); // Daftarkan ulang penangan sinyal untuk tindakan default
}

ke dalamutama(){
sinyal(TANDA,sig_handler); // Daftarkan penangan sinyal
untuk(ke dalamSaya=1;;Saya++){ //loop tak terbatas
printf ('%d : Di dalam fungsi utama ',Saya);
tidur(1); // Tunda selama 1 detik
}
kembali 0;
}

Pada tangkapan layar dari output Example3.c, kita dapat melihat bahwa ketika pengguna pertama kali mengetik Ctrl+C, fungsi handler dipanggil. Dalam fungsi handler, handler sinyal mendaftar ulang ke SIG_DFL untuk tindakan default sinyal. Ketika pengguna mengetik Ctrl+C untuk kedua kalinya, proses dihentikan yang merupakan tindakan default TANDA sinyal.

Mengirim Sinyal:

Suatu proses juga dapat secara eksplisit mengirim sinyal ke dirinya sendiri atau ke proses lain. fungsi raise() dan kill() dapat digunakan untuk mengirim sinyal. Kedua fungsi dideklarasikan dalam file header signal.h.

ke dalam menaikkan (ke dalamtanda)

Fungsi raise() digunakan untuk mengirim sinyal tanda ke proses pemanggilan (itu sendiri). Ini mengembalikan nol jika berhasil dan nilai bukan nol jika gagal.

ke dalammembunuh(pid_t pid, ke dalamtanda)

Fungsi mematikan yang digunakan untuk mengirim sinyal tanda ke proses atau grup proses yang ditentukan oleh pid .

Contoh Penangan Sinyal SIGUSR1

#termasuk
#termasuk

ruang kosongsig_handler(ke dalamtanda){
printf ('Fungsi penangan di dalam ');
}

ke dalamutama(){
sinyal(SIGUSR1,sig_handler); // Daftarkan penangan sinyal
printf ('Di dalam fungsi utama ');
menaikkan (SIGUSR1);
printf ('Di dalam fungsi utama ');
kembali 0;
}

Di sini, proses mengirim sinyal SIGUSR1 ke dirinya sendiri menggunakan fungsi raise().

Raise dengan Kill Contoh Program

#termasuk
#termasuk
#termasuk
ruang kosongsig_handler(ke dalamtanda){
printf ('Fungsi penangan di dalam ');
}

ke dalamutama(){
pid_t pid;
sinyal(SIGUSR1,sig_handler); // Daftarkan penangan sinyal
printf ('Di dalam fungsi utama ');
pid=getpid(); //Proses ID itu sendiri
membunuh(pid,SIGUSR1); // Kirim SIGUSR1 ke dirinya sendiri
printf ('Di dalam fungsi utama ');
kembali 0;
}

Di sini, proses kirim SIGUSR1 sinyal ke dirinya sendiri menggunakan membunuh() fungsi. getpid() digunakan untuk mendapatkan ID proses itu sendiri.

Pada contoh berikutnya kita akan melihat bagaimana proses induk dan anak berkomunikasi (Inter Process Communication) menggunakan membunuh() dan fungsi sinyal.

Komunikasi Orang Tua Anak dengan Sinyal

#termasuk
#termasuk
#termasuk
#termasuk
ruang kosongsig_handler_parent(ke dalamtanda){
printf ('Orang tua: Menerima sinyal respons dari anak ');
}

ruang kosongsig_handler_child(ke dalamtanda){
printf ('Anak: Menerima sinyal dari orang tua ');
tidur(1);
membunuh(getppid(),SIGUSR1);
}

ke dalamutama(){
pid_t pid;
jika((pid=garpu())<0){
printf ('Garpu Gagal ');
keluar (1);
}
/* Proses Anak */
lain jika(pid==0){
sinyal(SIGUSR1,sig_handler_child); // Daftarkan penangan sinyal
printf ('Anak: menunggu sinyal ');
berhenti sebentar();
}
/* Proses Induk */
lain{
sinyal(SIGUSR1,sig_handler_parent); // Daftarkan penangan sinyal
tidur(1);
printf ('Orang tua: mengirim sinyal ke Anak ');
membunuh(pid,SIGUSR1);
printf ('Orang tua: menunggu jawaban ');
berhenti sebentar();
}
kembali 0;
}

Di Sini, garpu() fungsi membuat proses anak dan mengembalikan nol ke proses anak dan ID proses anak ke proses induk. Jadi, pid telah diperiksa untuk memutuskan proses induk dan anak. Pada proses induk, ia ditidurkan selama 1 detik sehingga proses anak dapat mendaftarkan fungsi pengendali sinyal dan menunggu sinyal dari induk. Setelah 1 detik proses induk kirim SIGUSR1 sinyal ke anak memproses dan menunggu sinyal respons dari anak. Dalam proses anak, pertama menunggu sinyal dari orang tua dan ketika sinyal diterima, fungsi handler dipanggil. Dari fungsi handler, proses anak mengirimkan yang lain SIGUSR1 sinyal ke orang tua. Di Sini getppid() fungsi digunakan untuk mendapatkan ID proses induk.

Kesimpulan

Sinyal di Linux adalah topik besar. Dalam artikel ini kita telah melihat bagaimana menangani sinyal dari yang paling dasar, dan juga mendapatkan pengetahuan bagaimana sinyal dihasilkan, bagaimana suatu proses dapat mengirim sinyal ke dirinya sendiri dan proses lainnya, bagaimana sinyal dapat digunakan untuk komunikasi antar proses.