Nói ngắn gọn:
sigaction()
là tốt và được xác định rõ, nhưng là một chức năng của Linux và vì vậy nó chỉ hoạt động trên Linux. signal()
là xấu và được định nghĩa kém, nhưng là một hàm tiêu chuẩn C và vì vậy nó hoạt động trên mọi thứ.
Các trang người Linux nói gì về nó?
man 2 signal
(xem nó trực tuyến ở đây ) nêu:
Hành vi của signal () khác nhau giữa các phiên bản UNIX và cũng đã thay đổi theo lịch sử trên các phiên bản Linux khác nhau. Tránh sử dụng của nó: sử dụng sigaction(2)
thay thế. Xem tính di động dưới đây.
Tính di động Việc sử dụng tín hiệu di động () di động duy nhất là đặt bố trí tín hiệu thành SIG_DFL hoặc SIG_IGN. Các ngữ nghĩa khi sử dụng tín hiệu () để thiết lập trình xử lý tín hiệu khác nhau giữa các hệ thống (và POSIX.1 cho phép rõ ràng sự thay đổi này); không sử dụng nó cho mục đích này.
Nói cách khác: không sử dụng signal()
. Sử dụng sigaction()
thay thế!
GCC nghĩ gì?
Lưu ý tương thích: Như đã nói ở trên signal
, nên tránh chức năng này khi có thể. sigaction
là phương pháp ưa thích.
Nguồn: https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-Handling
Vì vậy, nếu cả Linux và GCC đều nói không sử dụng signal()
mà sigaction()
thay vào đó, sẽ đặt ra câu hỏi: làm thế nào để chúng ta sử dụng cái này khó hiểusigaction()
thứ này!?
Ví dụ sử dụng:
Đọc signal()
ví dụ TUYỆT VỜI của GCC tại đây: https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-Handling
Và sigaction()
ví dụ TUYỆT VỜI của họ ở đây: https://www.gnu.org/software/libc/manual/html_node/Sigaction-Function-Example.html
Sau khi đọc những trang đó, tôi đã nghĩ ra kỹ thuật sau đây cho sigaction()
:
1. sigaction()
, vì đó là cách đúng để gắn bộ xử lý tín hiệu, như được mô tả ở trên:
#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. Và cho signal()
mặc dù không phải là cách tốt để gắn bộ xử lý tín hiệu, như được mô tả ở trên, vẫn rất tốt để biết cách sử dụng nó.
Đây là mã trình diễn GCC được sao chép, vì nó sẽ tốt như nó sẽ nhận được:
#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);
…
}
Các liên kết chính cần lưu ý:
- Tín hiệu chuẩn: https://www.gnu.org/software/libc/manual/html_node/Stiteria-Signals.html#St Chuẩn-Signals
- Tín hiệu chấm dứt: https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html#Termination-Signals
- Xử lý tín hiệu cơ bản, bao gồm
signal()
ví dụ sử dụng GCC chính thức : https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-Handling
sigaction()
Ví dụ sử dụng GCC chính thức : https://www.gnu.org/software/libc/manual/html_node/Sigaction-Function-Example.html
- Bộ tín hiệu, bao gồm
sigemptyset()
và sigfillset()
; Tôi vẫn không hiểu chính xác những điều này, nhưng biết rằng chúng rất quan trọng: https://www.gnu.org/software/libc/manual/html_node/Signal-Sets.html
Xem thêm:
- Hướng dẫn Xử lý tín hiệu C ++ [với mã trình diễn xuất sắc]: https://www.tutorialspoint.com/cplusplus/cpp_signal_handling.htmlm
- https: //www.tutorialspoint.com/c_stiteria_l Library / signal_h.htm
signal
này thực sự là về hành vi của Unix System V. POSIX cho phép hành vi này hoặc hành vi BSD lành mạnh hơn nhiều, nhưng vì bạn không thể chắc chắn mình sẽ nhận được hành vi nào, nên vẫn tốt nhất để sử dụngsigaction
.