Kısacası:
sigaction()
iyi ve iyi tanımlanmış, ancak bir Linux işlevidir ve bu nedenle yalnızca Linux'ta çalışır. signal()
Kötü ve kötü tanımlanmış, ancak C standart bir işlevdir ve bu nedenle her şey üzerinde çalışır.
Linux kılavuz sayfaları bu konuda ne söylüyor?
man 2 signal
( buradan çevrimiçi görün ):
Signal () davranışı UNIX sürümleri arasında değişiklik gösterir ve aynı zamanda tarihsel olarak farklı Linux sürümleri arasında da değişiklik gösterir. Kullanımından kaçının: sigaction(2)
bunun yerine kullanın. Aşağıdaki Taşınabilirlik konusuna bakın.
Taşınabilirlik Signal () 'nın tek taşınabilir kullanımı, bir sinyalin düzenini SIG_DFL veya SIG_IGN olarak ayarlamaktır. Bir sinyal işleyici oluşturmak için signal () kullanılırken semantik sistemler arasında değişiklik gösterir (ve POSIX.1 bu varyasyona açıkça izin verir); bu amaçla kullanmayın.
Başka bir deyişle: kullanma signal()
. sigaction()
Bunun yerine kullanın !
GCC ne düşünüyor?
Uyumluluk Not: Yukarıda belirtildiği gibi signal
, bu işlevden mümkün olduğunca kaçınılmalıdır. sigaction
tercih edilen yöntemdir.
Kaynak: https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-Handling
Peki, hem Linux hem de GCC signal()
kullanmamayı sigaction()
değil, kullanmayı tercih ederse, bu şu soruyu akla getiriyor: Bu kafa karıştırıcı sigaction()
şeyi nasıl kullanıyoruz !?
Kullanım örnekleri:
GCC'nin MÜKEMMEL signal()
örneğini buradan okuyun : https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-Handling
Ve sigaction()
buradaki MÜKEMMEL örneği: https://www.gnu.org/software/libc/manual/html_node/Sigaction-Function-Example.html
Bu sayfaları okuduktan sonra aşağıdaki tekniği buldum sigaction()
:
1. sigaction()
, yukarıda açıklandığı gibi bir sinyal işleyici takmanın doğru yolu olduğundan:
#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. Ve signal()
, yukarıda açıklandığı gibi, bir sinyal işleyici takmanın iyi bir yolu olmasa da, nasıl kullanılacağını bilmek hala iyidir.
İşte GCC gösteri kodu kopyalandı, çünkü alacağı kadar iyi:
#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);
…
}
Dikkat edilmesi gereken ana bağlantılar:
- Standart Sinyaller: https://www.gnu.org/software/libc/manual/html_node/Standard-Signals.html#Standard-Signals
- Sonlandırma Sinyalleri: https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html#Termination-Signals
- Resmi GCC
signal()
kullanım örneği dahil olmak üzere Temel Sinyal İşleme : https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-Handling
- Resmi GCC
sigaction()
kullanım örneği: https://www.gnu.org/software/libc/manual/html_node/Sigaction-Function-Example.html
- Sinyal setleri,
sigemptyset()
ve dahil sigfillset()
; Bunları hala tam olarak anlayamıyorum, ancak önemli olduklarını biliyorum: https://www.gnu.org/software/libc/manual/html_node/Signal-Sets.html
Ayrıca bakınız:
- Nokta C ++ Sinyal İşleme [mükemmel demo koduyla]: https://www.tutorialspoint.com/cplusplus/cpp_signal_handling.htm
- https://www.tutorialspoint.com/c_standard_library/signal_h.htm
signal
aslında Unix System V davranışına aittir. POSIX, bu davranışa veya çok daha aklı başında BSD davranışına izin verir, ancak hangisini alacağınızdan emin olamayacağınız için, yine de kullanmak en iyisidirsigaction
.