“While driving on the roadside, what do you do when you have an encounter with a red signal? You stop driving for a while to wait for your turn until the signal turns green. Similarly, when a signal has an orange color, you continue to drive and never stop. POSIX Signals work the same as the traffic signal works. The POSIX Signal library came up with a very simple function to be utilized in the C code to generate signals, make your programs wait for their execution, and many more. This article would be demonstrating all those signal functions. We have been starting our examples with the creation and opening of a C file.”
Example 01
Within the very first POSIX example of signals, we are going to demonstrate the use of a simple signal() function to create and invoke a signal. Therefore, we have been using the signal.h library of C to utilize the signal functions, the stdio.h library is used for standard output and input functions and the unistd.h library is used to use user-defined structures, i.e., functions. The code contains a simple Handler function named “Handle” with integer type argument “s.” This variable “s” will be working as a signal. It contains a simple printf statement to send a signal “stop” to the user.
The main() function starts by creating a signal using the “signal” function here while using its option “SIGINT” to initialize a signal and the “Handle” function to use this function as a signal handler. The “for” loop starts from “1,” but it has no end, i.e., it’s going to increment but never stops until you do it yourself by exiting the program. The loop contains a printf statement of C to display that we are currently in the Main() function. By utilizing the Ctrl+C shortcut, we can invoke the Handle() function to display a signal message.
On each iteration of the “for” loop, it sleeps for 5 seconds and then gets incremented. Let’s execute our signal C code after properly saving and removing its errors.
When you run this program with the compiler of “C” and execute it with the “.a/.out” query, you will see an infinite execution of the main() thread.
When we pressed “Ctrl+C” to invoke the signal handler function, the Handle() function gets executed, and it displayed “Stop” at the moment. After that, the control again goes to the main() method, and it again starts to execute its printf statement using the infinite “for” loop. We pressed the shortcut key “Ctrl+Z” to forcefully stop this program.
Let’s say you want to ignore the signal invoked by a user. This can be done using the SIG_IGN parameter of the signal() function without using any handler function. We are using the same code with a slight change in the signal() function. Using this function, when a user invokes a signal using the “Ctrl+C” shortcut, the program will ignore the signal and continue to execute the main() function thread. Let’s just quickly save and execute this program to see the output.
#include <signal.h>
#include <unistd.h>
int main() {
signal(SIGINT, SIG_IGN);
for(int i=1;; i++) {
printf("%d: Ignoring the signal........\n", i);
sleep(5); }
return 0;
}
After this code execution, the main() function printf() statement continues to execute even after using the “Ctrl+C” shortcut. So, we forcefully stopped the program at the end.
Example 02
If you want to automatically raise a signal for your C program without using the Ctrl+C shortcut key, you can do that as well by utilizing the raise() function of the signal library. Therefore, we have updated the code from the first example and added a Handle() function once again. The main() function starts with the creation of a signal using the signal() function by passing it an option “SIGUSR1” with the “Handle” function in the parameters. This SIGUSSR1 option is the key to generating an automatic signal. The “for” loop sleeps for 10 seconds after executing the printf statement and then calls the raise() function with the option SIGUSR1 to generate an automatic signal by calling the “Handle” function. That’s it; we are ready to execute this program for now.
After the successful compilation, the execution takes place. The main() thread gpt is executed, and the program sleeps for 10 seconds while it’s in the loop.
After 10 seconds, the raise function has been invoked to generate an automatic signal by calling the Handle function. The execution sleeps for the next 5 seconds in the Handle function.
The control is given back to the main() function “loop,” and this process continues until you exit the program willingly by using the Ctrl+Z shortcut.
Just like your automatic signal for your program, you can also kill the signal after it’s invoking and send the signal to a processing group. In other words, the “kill” function of the POSIX C signals library has been used to send alerts to the program’s group. Therefore, we have updated our main program along with its Handle function in the above-shown image code. The pid_t object is used to create an ID “p” for the process. The signal() function is called here to create a signal through the use of the Handle() function defined before from the main function.
The getpid() function is called within the “for” loop to get the process ID of this thread and save it to a variable “p”. This process id “p” is passed to the “kill” function along with the option SIGUSR1 to kill the signal and send its report to a progress group. Then, a program sleeps for 8 seconds and prints “Back in Main” while the loop continues.
The function gets executed, sends the signal to the process group, and sleeps for 8 seconds.
The “Back in Main” got executed, and the loop continued the same processing.
Conclusion
This guide has been demonstrating the use of signal functions in the C program to make your work environment more efficient. For this, we have tried the POSIX’s signal() function, kill() function, and raise() function along with the SIGINT, SIG_IGN, and SIGUSR1 options in the functions.