in the Linux: On the signal in the blog post we wrote a mysleep, but in fact this function in the multi-threaded environment will be wrong, that is, our mysleep function is not reentrant function,
Now re-examine the "mysleep" program and imagine the timing:
1. Register the processing function of the SIGALRM signal.
2. Call Alarm (NSECS) to set the alarm.
3. A process with higher kernel scheduling overrides the current process execution, and there are many higher priority processes, each of which takes a long time to execute
4. Nsecs seconds after the alarm clock expires, the kernel sends SIGALRM signal to this process, in a pending state.
5. The higher-priority process is finished, and the kernel is dispatched back to the process execution. SIGALRM Signal delivery, executive branch
function Sig_alrm and then enter the kernel again.
6. Return the main control flow for this process, alarm (nsecs), call pause () to suspend the wait.
7. But the SIGALRM signal has been processed, what is waiting?
The root cause of this problem is that the timing of the system's operation (Timing) is not as we thought when we wrote the program. Although alarm (NSECS) is followed by pause (), there is no guarantee that pause () will be called within nsecs seconds after calling alarm (nsecs). Because asynchronous events can happen at any time (where asynchronous events refer to higher-priority processes), if we are poorly considered when writing programs, we can cause errors due to timing problems, called race conditions (racecondition).
In fact, it is the priority preemption of the process execution sequence in the operating system. Or a process interrupt that is made after the current execution time slice in the process completes.
How to solve the above problem? The reader may think of masking the SIGALRM signal before calling pause so that it does not pass in advance. See how this works?
1. Shielding SIGALRM signal;
2. Alarm (NSECS);
3. Remove the shield from the SIGALRM signal;
4. Pause ();
There is a gap between the unblocking of the signal and the call to pause, and it is still possible for SIGALRM to pass through this gap. To eliminate this gap, can we move the unblock behind pause?
1. Shielding SIGALRM signal;
2. Alarm (NSECS);
3. Pause ();
4. Remove the shield from the SIGALRM signal;
This is even worse, it is not possible to call Pause,pause without unblocking the SIGALRM signal at all. It would be nice if the two steps "unblock" and "hang Wait" could be combined into an atomic operation, which is the function of the Sigsuspend function. Sigsuspend includes the suspend wait function of pause and solves the problem of race condition, and should call sigsuspend instead of pause in the case of strict timing requirements.
#include <signal.h>int sigsuspend (const sigset_t *sigmask);
Like pause, Sigsuspend has no successful return value, only sigsuspend returns after a signal handler has been executed, and the return value is -1,errno set to Eintr. When Sigsuspend is called, the signal screen word of the process is specified by the Sigmask parameter, which temporarily unlocks a signal by specifying the Sigmask, then suspends the wait, and when Sigsuspend returns, the signal screen word of the process reverts to the original
To the value, if the original signal is masked, from the sigsuspend back is still shielded.
Here's a look at the modified Mysleep:
#include <stdio.h> #include <signal.h>void handle (int sig) { printf ("i get a sig %d\n", sig);} Int sleep (int time) { struct sigaction oldact,newact; sigset_t newmask,oldmask,suspmask; newact.sa_handler=handle; newact.sa_flags=0; sigemptyset (&newact.sa_mask); sigaction (sigalrm,&newact,&oldact);//register SIGALRM's signal processing function sigemptyset ( &newmask); sigaddset (&NEWMASK,SIGALRM); sigprocmask (SIG_ Block,&newmask,&oldmask);//shielding SIGALRM signal; alarm (time); Suspmask=oldmask; sigdelset (&SUSPMASK,SIGALRM);//unblock SIGALRM signal in Suspmask; sigsuspend (&suspmask);//use Suspmask to replace the block table in the PCB to remove the SIGALRM signalThe blocking int ret=alarm (0); sigaction (SIGALRM,&oldact,NULL); sigprocmask (sig_setmask,&oldmask,null);//system default processing signal mode before recovery Return ret;} Int main () { while (1) { printf ("i am sleep\n"); sleep (5); } return 0;}
Let's focus on a signal sigchld:
SIGCHLD is the return signal to the parent process at the end of the child process, but for this signal, the default action of the system is ignored.
In previous processes, both parent and child processes cleaned up the zombie process using the waitpid,wait function, and the parent process ended up waiting to clean up the child process in a blocking/nonblocking manner, but that would increase the execution pressure of the parent process.
So we use the SIGCHLD signal passed at the end of the child process to notify the parent process, which improves the efficiency of running between the parent and child processes and cleans up the child process after passing the SIGCHLD:
Code:
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h>void my_ SIGCHLD (Int sig) { int status=0; pid_t ret; while ((Ret=waitpid ( -1,&status,0)) >0) { printf ("sig: %d,code: %d\n", Status&0xff, (status>>8) &0xff ); }}int main () { pid_t tid=fork (); if (tid<0) { perror ("fork"); exit (1); } else if (tid==0) { sleep (10);// Ensure that the parent process has registered the signal handler function, parent, child process who first runs the indeterminate printf ("child is Quit!\n "); &nBsp; exit (1); } else { signal (SIGCHLD,MY_SIGCHLD); while (1); } return 0;}
Note: In MY_SIGCHLD, note the while loop to wait for the waitpid, to ensure that in a multi-process environment for the child process cleanup, if and not while, because the SIGCHLD signal can not be collected multiple times, the outstanding existence can only prove that there is and nothing, So for the parent process. We need constant waitpid to wait and know that the wait is failing.
This article is from the "egg-left" blog, please be sure to keep this source http://memory73.blog.51cto.com/10530560/1771250
Linux: Under the signal