There are many days did not write a blog, think about it or not to waste time, write something to record their growth or hundred profit without harm. Today is September 17, summer vacation in a game company internship for some time, do things in C + + on Windows to write some game hero skills logic implementation. Although the time is not long, but also learned a little things, the team project development process also has an intuitive feeling, the project c++11 new features are also useful to many, especially the lambda expression, some of the STL's containers and algorithms finally have a place to practice. Because I prefer Linux C, there is no intention to leave, now back to school, a good review for a period of time, prepare for school recruit bar. If a friend has a job opportunity, may wish to recommend me O (∩_∩) o, my email:[email protected]. Seems to be a bit far away, long time not to write things.
Basic concepts of signals
Talking about Linux programming signal is a very important piece of content. There is a detailed introduction to the Manual of Signal,linux. Specific: Man 7 signal. I won't waste my space on it.
The signal is considered a software interrupt (as distinct from a hardware interrupt). The signaling mechanism provides a way to handle asynchronous events under a single process/thread. The process is when the process runs somewhere, receives a signal, retains the "live", responds to the signal (note that the response here is a macro-sense response, and that the ignore of the signal (sig_ign) is also considered a response, followed by a detailed approach to the signal response.) ) to continue running where it was just saved. I made a GIF that might be a clear way to deal with this:
There are many conditions for generating the signal, some key combinations (Ctrl + C, CTRL+\,CTRL+Z, etc.), kill command, kill system call, and some signals generated by the kernel (such as the kernel detects a segment error, a pipe burst, etc.). It is important to note that when we send a signal to be restricted by permission, it is illegal to send a signal to another process without permission (the rules about permissions will be summarized later in the blog). There are many kinds of signals, all of which are named in the form of sig+ names, and usually have practical meanings and usages that can be consulted manual. There are some common signals that need to be memorized such as Sigint,sigchld,sigio and so on. When writing a program, we'd better use the form of a signal macro, which is more readable. So how do you "respond" to the signal?
One of the interfaces of signal processing signal ()
For most of the signals, the Linux system has a default processing method. Most of the default processing is to terminate the program and dump the core file. To process the signal, the Linux system handles the signal interface with two sigaction (), signal (), and the simpler is the signal () function, in the form of the following:
typedef void (*sighandler_t) (int);
sighandler_t signal (int signum, sighandler_t handler);
The SIGANL () function has two parameters where an int parameter is the signal to be processed, such as a SIGINT macro. Another function pointer with the parameter type sighandler_t, handler the function that the pointer corresponds to We call it: Signal processing function (Signal-handler functions). The second parameter of the visible signal () is a signal handler function, and the return value is also a signal handler function, which fails to return the macro Sig_err. Such classic forms of functions are often encountered on Linux. The action of the signal () function is to establish a SIGNUM signal processing function (establish a signal handler function). Popular point is that when the signum signal arrives, the process saves the current process stack and goes to execute the handler function specified in Siganl (). As mentioned before, there are many ways to respond to a signal, so handler can be not only a function pointer but also a macro defined by ISO C for us: Sig_ign,sig_del, like their name sig_ign is ignoring this signal, sig_ Del is the default way to maintain this signal (the default processing can also be sig_ign, more around, but reasonable). The three macro definitions mentioned earlier are as follows (/usr/include/bits/signum.h):
#define SIG_ERR ((__sighandler_t)-1)
#define SIG_DFL ((__sighandler_t) 0)
#define SIG_IGN ((__sighandler_t) 1)
Below I write a small demo demo How to write a signal processing function:
#include <signal.h> #include <stdio.h> void Sigdemo (int SIG) {printf ( receive a signal:%s\n Span style= "color: #800000;" > " ,strsignal (SIG);} int main () {if (signal (sigint,sigdemo) = = Sig_err)
{
Perror ("Signal ()");
return;
}
printf ( " main started.\n ); Pause (); // wait a signal. }
As you can see, I do not actively invoke the SIGDEMO function in the main function, but after running the program, when we break down CTRL + C (sending the SIGINT signal, the macro corresponds to a value of 2), there is a result:
[Baixiang ~$]a.out Main started. ^creceive a signal:2
The visible Sigdemo function is executed, and its parameter sig is the value of the received signal. To convert the value of the signal to its meaning string.h provides a function char* strsignal (int sig), basically see the function prototype will know how to use this function, I will not waste space to repeat.
Send Signal
Above we send the signal SIGINT to the current process by using CTRL + C key combination. However, this method only sends a small number of signals and does not apply to all processes such as background processes and daemons. Daemons don't have to say that they don't even have a terminal. The interactive shell (interactive shell) automatically sets the interrupt and exit signals to ignore when starting a background process, which I see on the Internet a good blog: http://hongjiang.info/ shell-script-background-process-ignore-sigint/. In this case, you cannot use the shortcut key. Here I describe several other ways to send a signal.
The first is the shell command Kill, which uses the following:
Kill [-S signal|-p] [-Q sigval] [-a] [--] pid ...
-s signal signal can be a macro such as sigint,sigquit, or a one-to-one ... this value can be used as you please.
-Q Queue Sigval is a value that can be accompanied by a signal, but this can only be an integer, which can be received by using sigaction () in the process, which corresponds to another function, Sigqueue (). This is not covered in detail here, as discussed below.
The PID is the process ID of the target process, which can be one or more. But when sending a signal, make sure that the user you are using has the right to send a signal to the target process.
Kill has more options than that, but it's usually enough. Please check your own "Man 1 Kill" if you are interested.
and the shell command kill has a system called Kill () with the same name, and its prototype is this:
int Kill (pid_t pid, int sig);
Believe that the above shell command, the use of this function is at a glance. The PID is the pid,sig of the target process is the signal to be sent. As with other functions it is also successful to return 0, failure-1. But is it really that simple? Actually, it's not. This parameter of PID is very learned here. Its value can be not just a process ID, it can even be negative. If you are familiar with programming Linux, this usage must have come into contact with the MSGRCV () function used to get Message Queuing, where the Msgtype parameter also has a similar usage. Of course it's far.
pid>0 At this time formally the most common one situation, PID is to target the process of PID.
Pid=0 then Kill () sends the signal to all processes in the same group as the calling process, including himself.
Pid=-1 then the signal will be sent to all of the processes it has permission to send signals (except the INIT process and the calling process).
The pid<-1 signal sends the SIG signal to each process in the process group with the group ID equal to the absolute value of the PID .
If the PID is not matched to the target process in the above four cases, then the -1,errno is returned to Esrch. When no permission is sent, Kill () also fails to return -1,errno will be set to Eperm. For details on how permissions work on Linux, I'm going to try to summarize the blog behind it.
Similar to Kill () also has a function killpg (), the usage is much simpler, also does not waste the space, the view manual can take care of.
The last function to send a signal is raise (), which takes only one parameter signal and then passes that signal to the calling process:
int raise (int sig);//Successful return 0, failure return-1
Since this function does not need to refer to the process ID, it is a function that is incorporated into the C99 standard.
In addition to these kinds of signal-generating shell commands and functions, there are some cases where signals can be generated, such as alarm (), SetTimer (), and some time-related functions, as well as some common hardware and software errors that will produce a signal. In detail these seem to be a little diluted theme, pulled away.
The semantics of unreliable signals and reliable signals
The reliable and unreliable signal is mainly embodied in two aspects:
- For unreliable signals, the processing of the signal is set to the default action each time the signal is processed by the process. For a reliable signal, the processing of the signal will not change after its function is executed.
- The signal may be lost. (See the difference between real-time and non-real-time signals in the next section).
Linux still supports these early unreliable signals because the Linux signaling mechanism is basically ported from the signaling mechanisms on the early UNIX systems. But Linux also made an improvement on unreliable signals (the first dot of the two-point distinction above), i.e. unreliable signal processing, which does not become the default after the processing function executes. Therefore, the difference between unreliable and reliable signals on Linux is whether queuing is supported.
As to whether the signal will be lost, let's look at these two pieces of code, first of all RCV.C
1#include <signal.h>2#include <stdio.h>3#include <stdlib.h>4#include <string.h>5#include <unistd.h>6 7 voidFunintSig)8 {9printf"recvive a signal:%s\n", Strsignal (SIG));Ten } One A intMain () - { - if(Signal (sigint,fun) = =Sig_err) thePerror ("Signal"); -printf"%d\n", Getpid ()); - while(1) - pause (); +}
This procedure first installs the SIGINT signal processing function Fun,fun function just prints the signal information. The process ID is then printed out while the loop waits for the signal.
Another procedure is SEND.C:
1#include <signal.h>2#include <stdlib.h>3#include <stdio.h>4 5 intMainintargcChar**argv)6 {7pid_t pid = (pid_t) atol (argv[1]);8printf"%d\n", PID);9 inti =0;Ten for(; i<5xx;++i) OneKill (Pid,sigint); A}
The send program receives a parameter from the terminal that is the PID of the target process and sends it 500 times to the SIGINT signal. Let's compile the rcv.c,send.c into RCV and send respectively. Run RCV first, print out the process PID 20273 then we run send 20273 on a terminal and observe the result:
Send clearly sent 500 SIGINT signal, and RCV only accept processing 13 SIGINT signal, this is what? Tomorrow will continue to write down, today is too late, fighting less than a little sleepy.
Analysis of signal mechanism in Linux (i.)