Bagaimana cara menggunakan pengendali isyarat dalam bahasa C?

How Use Signal Handlers C Language



Dalam artikel ini kami akan menunjukkan kepada anda cara menggunakan pengendali isyarat di Linux menggunakan bahasa C. Tetapi pertama-tama kita akan membincangkan apa itu isyarat, bagaimana ia akan menghasilkan beberapa isyarat biasa yang boleh anda gunakan dalam program anda dan kemudian kita akan melihat bagaimana pelbagai isyarat dapat dikendalikan oleh program semasa program dijalankan. Jadi, mari kita mulakan.

Isyarat

Isyarat adalah peristiwa yang dihasilkan untuk memberitahu proses atau utas bahawa beberapa situasi penting telah tiba. Apabila proses atau utas telah menerima isyarat, proses atau utas akan menghentikan apa yang dilakukannya dan mengambil tindakan. Isyarat mungkin berguna untuk komunikasi antara proses.







Isyarat Piawai

Isyarat ditentukan dalam fail tajuk isyarat.h sebagai pemalar makro. Nama isyarat telah dimulakan dengan SIG dan diikuti dengan penerangan ringkas mengenai isyarat. Jadi, setiap isyarat mempunyai nilai angka yang unik. Program anda harus selalu menggunakan nama isyarat, bukan nombor isyarat. Sebabnya ialah nombor isyarat boleh berbeza mengikut sistem tetapi makna nama akan menjadi standard.



Makro NSIG ialah jumlah isyarat yang ditentukan. Nilai NSIG adalah lebih besar daripada jumlah isyarat yang ditentukan (Semua nombor isyarat diperuntukkan berturut-turut).



Berikut adalah isyarat standard:





Nama Isyarat Penerangan
PENDAPATAN Menangguhkan proses. Isyarat SIGHUP digunakan untuk melaporkan pemutusan terminal pengguna, mungkin kerana sambungan jauh terputus atau terputus.
TANDATANGAN Selang proses. Apabila pengguna menaip watak INTR (biasanya Ctrl + C) isyarat SIGINT dihantar.
SIGQUIT Hentikan prosesnya. Apabila pengguna menaip karakter QUIT (biasanya Ctrl + ) isyarat SIGQUIT dihantar.
METERAI Arahan haram. Apabila percubaan dilakukan untuk melaksanakan sampah atau arahan istimewa, isyarat SIGILL dihasilkan. Juga, SIGILL dapat dihasilkan ketika tumpukan meluap, atau ketika sistem mengalami masalah menjalankan pengendali isyarat.
TANDATANGAN Perangkap jejak. Arahan breakpoint dan arahan perangkap lain akan menghasilkan isyarat SIGTRAP. Penyahpepijat menggunakan isyarat ini.
SIGABRT Batalkan. Isyarat SIGABRT dihasilkan semasa fungsi batal () dipanggil. Isyarat ini menunjukkan ralat yang dikesan oleh program itu sendiri dan dilaporkan oleh panggilan fungsi batalkan ().
SIGFPE Pengecualian titik terapung. Apabila berlaku kesalahan aritmetik maut, isyarat SIGFPE dihasilkan.
SIGUSR1 dan SIGUSR2 Isyarat SIGUSR1 dan SIGUSR2 boleh digunakan mengikut kehendak anda. Adalah berguna untuk menulis pengendali isyarat untuk mereka dalam program yang menerima isyarat untuk komunikasi antara proses yang mudah.

Tindakan Lalai Isyarat

Setiap isyarat mempunyai tindakan lalai, salah satu dari yang berikut:

Tempoh: Prosesnya akan berakhir.
Teras: Proses ini akan berakhir dan menghasilkan fail dump inti.
Ign: Prosesnya akan mengabaikan isyarat.
Berhenti: Prosesnya akan berhenti.
Akaun: Proses akan terus dihentikan.



Tindakan lalai boleh diubah menggunakan fungsi pengendali. Sebilangan tindakan lalai isyarat tidak dapat diubah. SIGKILL dan SIGABRT tindakan lalai isyarat tidak boleh diubah atau diabaikan.

Pengendalian Isyarat

Sekiranya proses menerima isyarat, proses tersebut mempunyai pilihan tindakan untuk jenis isyarat tersebut. Prosesnya boleh mengabaikan isyarat, dapat menentukan fungsi pengendali, atau menerima tindakan lalai untuk jenis isyarat tersebut.

  • Sekiranya tindakan yang ditentukan untuk isyarat diabaikan, maka isyarat tersebut akan segera dibuang.
  • Program ini dapat mendaftarkan fungsi pengendali menggunakan fungsi seperti isyarat atau sigaction . Ini dipanggil pengendali menangkap isyarat.
  • Sekiranya isyarat tidak ditangani atau diabaikan, tindakan lalai akan berlaku.

Kami dapat menangani isyarat menggunakan isyarat atau sigaction fungsi. Di sini kita melihat bagaimana yang paling mudah isyarat() fungsi digunakan untuk mengendalikan isyarat.

intisyarat() (inttanda, batal (*fungsi)(int))

The isyarat() akan memanggil fungsi berfungsi sekiranya proses tersebut menerima isyarat tanda . The isyarat() mengembalikan penunjuk untuk berfungsi fungsi jika berjaya atau mengembalikan kesalahan kepada errno dan -1 sebaliknya.

The fungsi penunjuk boleh mempunyai tiga nilai:

  1. SIG_DFL : Ini adalah penunjuk ke fungsi lalai sistem SIG_DFL () , diisytiharkan dalam h fail pengepala. Ia digunakan untuk mengambil tindakan lalai dari isyarat.
  2. SIG_IGN : Ia adalah penunjuk sistem yang mengabaikan fungsi SIG_IGN () , diisytiharkan dalam h fail pengepala.
  3. Penunjuk fungsi pengendali yang ditentukan pengguna : Jenis fungsi pengendali yang ditentukan pengguna adalah tidak sah (*) (int) , bermaksud jenis pengembalian adalah tidak sah dan satu argumen jenis int.

Contoh Pengendali Isyarat Asas

#sertakan
#sertakan
#sertakan
batalsig_handler(inttanda){

// Jenis fungsi pengendali yang dikembalikan mestilah tidak sah
printf (' nFungsi pengendali dalam n');
}

intutama(){
isyarat(TANDATANGAN,sig_handler); // Daftar pengendali isyarat
untuk(inti=1;;i++){ // Gelung tak terhingga
printf ('% d: Fungsi utama di dalam n',i);
tidur(1); // Kelewatan selama 1 saat
}
kembali 0;
}

Dalam tangkapan skrin output dari Contoh1.c, kita dapat melihat bahawa dalam fungsi utama gelung tak terbatas sedang dijalankan. Semasa pengguna menaip Ctrl + C, pelaksanaan fungsi utama berhenti dan fungsi pengendali isyarat dipanggil. Setelah selesai fungsi pengendali, pelaksanaan fungsi utama disambung semula. Apabila pengguna menaip Ctrl + , prosesnya berhenti.

Abaikan Contoh Isyarat

#sertakan
#sertakan
#sertakan
intutama(){
isyarat(TANDATANGAN,SIG_IGN); // Daftar pengendali isyarat kerana mengabaikan isyarat

untuk(inti=1;;i++){ // Gelung tak terhingga
printf ('% d: Fungsi utama di dalam n',i);
tidur(1); // Kelewatan selama 1 saat
}
kembali 0;
}

Di sini fungsi pengendali adalah mendaftar ke SIG_IGN () berfungsi untuk mengabaikan tindakan isyarat. Oleh itu, semasa pengguna menaip Ctrl + C, TANDATANGAN isyarat dihasilkan tetapi tindakannya tidak dipedulikan.

Contoh Pengendali semula Isyarat

#sertakan
#sertakan
#sertakan

batalsig_handler(inttanda){
printf (' nFungsi pengendali dalam n');
isyarat(TANDATANGAN,SIG_DFL); // Daftar semula pengendali isyarat untuk tindakan lalai
}

intutama(){
isyarat(TANDATANGAN,sig_handler); // Daftar pengendali isyarat
untuk(inti=1;;i++){ // Gelung tak terhingga
printf ('% d: Fungsi utama di dalam n',i);
tidur(1); // Kelewatan selama 1 saat
}
kembali 0;
}

Dalam tangkapan skrin output Contoh3.c, kita dapat melihat bahawa ketika pengguna pertama kali menaip Ctrl + C, fungsi pengendali dipanggil. Dalam fungsi pengendali, pengendali isyarat mendaftar semula ke SIG_DFL untuk tindakan lalai isyarat. Apabila pengguna menaip Ctrl + C untuk kali kedua, proses ditamatkan yang merupakan tindakan lalai dari TANDATANGAN isyarat.

Menghantar Isyarat:

Proses juga secara eksplisit dapat menghantar isyarat kepada dirinya sendiri atau ke proses lain. Fungsi menaikkan () dan membunuh () dapat digunakan untuk menghantar isyarat. Kedua fungsi tersebut dinyatakan dalam fail header signal.h.

int menaikkan (inttanda)

Fungsi kenaikan () digunakan untuk menghantar isyarat tanda ke proses panggilan (itu sendiri). Ia mengembalikan sifar jika berjaya dan nilai bukan sifar jika gagal.

intbunuh(pid_t pid, inttanda)

Fungsi kill digunakan untuk menghantar isyarat tanda kepada proses atau kumpulan proses yang ditentukan oleh pid .

Contoh Penangan Isyarat SIGUSR1

#sertakan
#sertakan

batalsig_handler(inttanda){
printf ('Fungsi pengendali dalam n');
}

intutama(){
isyarat(SIGUSR1,sig_handler); // Daftar pengendali isyarat
printf ('Fungsi utama di dalam n');
menaikkan (SIGUSR1);
printf ('Fungsi utama di dalam n');
kembali 0;
}

Di sini, proses menghantar isyarat SIGUSR1 kepada dirinya sendiri menggunakan fungsi kenaikan ().

Naik dengan Program Contoh Bunuh

#sertakan
#sertakan
#sertakan
batalsig_handler(inttanda){
printf ('Fungsi pengendali dalam n');
}

intutama(){
pid_t pid;
isyarat(SIGUSR1,sig_handler); // Daftar pengendali isyarat
printf ('Fungsi utama di dalam n');
pid=getpid(); // Proses ID itu sendiri
bunuh(pid,SIGUSR1); // Hantarkan SIGUSR1 kepada dirinya sendiri
printf ('Fungsi utama di dalam n');
kembali 0;
}

Di sini, proses menghantar SIGUSR1 memberi isyarat kepada dirinya menggunakan bunuh() fungsi. getpid () digunakan untuk mendapatkan ID proses itu sendiri.

Dalam contoh seterusnya kita akan melihat bagaimana proses ibu bapa dan anak berkomunikasi (Inter Process Communication) menggunakan bunuh() dan fungsi isyarat.

Komunikasi Ibu Bapa dengan Isyarat

#sertakan
#sertakan
#sertakan
#sertakan
batalsig_handler_parent(inttanda){
printf ('Ibu bapa: Menerima isyarat tindak balas daripada anak n');
}

batalsig_handler_child(inttanda){
printf ('Anak: Menerima isyarat daripada ibu bapa n');
tidur(1);
bunuh(getppid(),SIGUSR1);
}

intutama(){
pid_t pid;
sekiranya((pid=garpu())<0){
printf ('Garpu Gagal n');
jalan keluar (1);
}
/ * Proses Kanak-kanak * /
yang lain sekiranya(pid==0){
isyarat(SIGUSR1,sig_handler_child); // Daftar pengendali isyarat
printf ('Anak: menunggu isyarat n');
berhenti seketika();
}
/ * Proses Ibu Bapa * /
yang lain{
isyarat(SIGUSR1,sig_handler_parent); // Daftar pengendali isyarat
tidur(1);
printf ('Ibu bapa: menghantar isyarat kepada Anak n');
bunuh(pid,SIGUSR1);
printf ('Ibu bapa: menunggu jawapan n');
berhenti seketika();
}
kembali 0;
}

Di sini, garpu () fungsi mencipta proses anak dan mengembalikan sifar ke proses anak dan ID proses anak ke proses ibu bapa. Jadi, pid telah diperiksa untuk menentukan proses ibu bapa dan anak. Dalam proses ibu bapa, ia tidur selama 1 saat sehingga proses anak dapat mendaftarkan fungsi pengendali isyarat dan menunggu isyarat dari ibu bapa. Selepas 1 ibu bapa proses menghantar SIGUSR1 memberi isyarat kepada proses anak dan tunggu isyarat tindak balas dari anak. Dalam proses anak, pertama ia menunggu isyarat dari ibu bapa dan apabila isyarat diterima, fungsi pengendali dipanggil. Dari fungsi pengendali, proses anak menghantar yang lain SIGUSR1 isyarat kepada ibu bapa. Di sini getppid () fungsi digunakan untuk mendapatkan ID proses ibu bapa.

Kesimpulannya

Isyarat di Linux adalah topik besar. Dalam artikel ini kita telah melihat bagaimana menangani isyarat dari yang sangat asas, dan juga mendapatkan pengetahuan bagaimana isyarat menghasilkan, bagaimana proses dapat mengirim isyarat kepada dirinya sendiri dan proses lain, bagaimana isyarat dapat digunakan untuk komunikasi antara proses.