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:
Perilaku sinyal () bervariasi antar versi UNIX, dan secara historis juga bervariasi di berbagai versi Linux. Hindari penggunaannya: gunakan sigaction(2)
saja. Lihat Portabilitas di bawah ini.
Portabilitas Satu-satunya penggunaan sinyal portabel () adalah untuk mengatur disposisi sinyal ke SIG_DFL atau SIG_IGN. Semantik saat menggunakan sinyal () untuk membentuk pengendali sinyal bervariasi di seluruh sistem (dan POSIX.1 secara eksplisit memungkinkan variasi ini); jangan menggunakannya untuk tujuan ini.
Dengan kata lain: jangan gunakan signal()
. Gunakan sigaction()
sebagai gantinya!
Apa yang dipikirkan GCC?
Catatan Kompatibilitas: Seperti disebutkan di atas untuk signal
, fungsi ini harus dihindari bila memungkinkan. sigaction
adalah metode yang disukai.
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 menggunakan sigaction()
, itu menimbulkan pertanyaan: bagaimana kita menggunakan hal yang membingungkan ini sigaction()
!?
Contoh Penggunaan:
Baca signal()
contoh EXCELLENT GCC di sini: https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-Handling
Dan sigaction()
contoh EXCELLENT mereka di sini: https://www.gnu.org/software/libc/manual/html_node/Sigaction-Function-Example.html
Setelah 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:
#include <errno.h> // errno
#include <signal.h> // sigaction()
#include <stdio.h> // printf()
#include <string.h> // strerror()
#define LOG_LOCATION __FILE__, __LINE__, __func__ // Format: const char *, unsigned int, const char *
#define LOG_FORMAT_STR "file: %s, line: %u, func: %s: "
/// @brief Callback function to handle termination signals, such as Ctrl + C
/// @param[in] signal Signal number of the signal being handled by this callback function
/// @return None
static void termination_handler(const int signal)
{
switch (signal)
{
case SIGINT:
printf("\nSIGINT (%i) (Ctrl + C) signal caught.\n", signal);
break;
case SIGTERM:
printf("\nSIGTERM (%i) (default `kill` or `killall`) signal caught.\n", signal);
break;
case SIGHUP:
printf("\nSIGHUP (%i) (\"hang-up\") signal caught.\n", signal);
break;
default:
printf("\nUnk signal (%i) caught.\n", signal);
break;
}
// DO PROGRAM CLEANUP HERE, such as freeing memory, closing files, etc.
exit(signal);
}
/// @brief Set a new signal handler action for a given signal
/// @details Only update the signals with our custom handler if they are NOT set to "signal ignore" (`SIG_IGN`),
/// which means they are currently intentionally ignored. GCC recommends this "because non-job-control
/// shells often ignore certain signals when starting children, and it is important for children
/// to respect this." See
/// https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-Handling
/// and https://www.gnu.org/software/libc/manual/html_node/Sigaction-Function-Example.html.
/// Note that termination signals can be found here:
/// https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html#Termination-Signals
/// @param[in] signal Signal to set to this action
/// @param[in] action Pointer to sigaction struct, including the callback function inside it, to attach to this signal
/// @return None
static inline void set_sigaction(int signal, const struct sigaction *action)
{
struct sigaction old_action;
// check current signal handler action to see if it's set to SIGNAL IGNORE
sigaction(signal, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN)
{
// set new signal handler action to what we want
int ret_code = sigaction(signal, action, NULL);
if (ret_code == -1)
{
printf(LOG_FORMAT_STR "sigaction failed when setting signal to %i;\n"
" errno = %i: %s\n", LOG_LOCATION, signal, errno, strerror(errno));
}
}
}
int main(int argc, char *argv[])
{
//...
// Register callbacks to handle kill signals; prefer the Linux function `sigaction()` over the C function
// `signal()`: "It is better to use sigaction if it is available since the results are much more reliable."
// Source: https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-Handling
// and /programming/231912/what-is-the-difference-between-sigaction-and-signal/232711#232711.
// See here for official gcc `sigaction()` demo, which this code is modeled after:
// https://www.gnu.org/software/libc/manual/html_node/Sigaction-Function-Example.html
// Set up the structure to specify the new action, per GCC's demo.
struct sigaction new_action;
new_action.sa_handler = termination_handler; // set callback function
sigemptyset(&new_action.sa_mask);
new_action.sa_flags = 0;
// SIGINT: ie: Ctrl + C kill signal
set_sigaction(SIGINT, &new_action);
// SIGTERM: termination signal--the default generated by `kill` and `killall`
set_sigaction(SIGTERM, &new_action);
// SIGHUP: "hang-up" signal due to lost connection
set_sigaction(SIGHUP, &new_action);
//...
}
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:
#include <signal.h>
void
termination_handler (int signum)
{
struct temp_file *p;
for (p = temp_file_list; p; p = p->next)
unlink (p->name);
}
int
main (void)
{
…
if (signal (SIGINT, termination_handler) == SIG_IGN)
signal (SIGINT, SIG_IGN);
if (signal (SIGHUP, termination_handler) == SIG_IGN)
signal (SIGHUP, SIG_IGN);
if (signal (SIGTERM, termination_handler) == SIG_IGN)
signal (SIGTERM, SIG_IGN);
…
}
Tautan utama yang harus diperhatikan:
- Sinyal Standar: https://www.gnu.org/software/libc/manual/html_node/Standard-Signals.html#Standard-Signals
- Sinyal Pengakhiran: https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html#Termination-Signals
- Penanganan Sinyal Dasar, termasuk
signal()
contoh penggunaan GCC resmi : https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-Handling
sigaction()
Contoh penggunaan GCC resmi : https://www.gnu.org/software/libc/manual/html_node/Sigaction-Function-Example.html
- Kumpulan sinyal, termasuk
sigemptyset()
dan sigfillset()
; Saya masih tidak mengerti persis ini, tetapi tahu itu penting: https://www.gnu.org/software/libc/manual/html_node/Signal-Sets.html
Lihat juga:
- TutorialsPoint C ++ Penanganan Sinyal [dengan kode demo luar biasa]: https://www.tutorialspoint.com/cplusplus/cpp_signal_handling.htm
- https://www.tutorialspoint.com/c_standard_library/signal_h.htm
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
.