当前位置:网站首页>Sequential state

Sequential state

2022-04-23 20:46:00 baboon_ chen

One 、pause function

#include <unistd.h>
int pause(void);

/*  Return value ( success ):-1,  And set up errno by EINTR 1、 If the default processing action of the signal is to terminate the process , The process terminates ,pause Function has no chance to return . 2、 If the default processing action of the signal is to ignore , The process continues to be suspended ,pause Function does not return . 3、 If the signal processing action is to capture , After calling the signal processing function ,pause return -1. 4、pause The received signal cannot be shielded , If it's blocked , that pause Can't be awakened . */

   Calling this function can cause the process to actively suspend , Wait for the signal to wake up . The process that calls the system call will be blocked ( Give up on your own initiative CPU) Until a signal is sent to everyone to wake it up .

Two 、 What is a sequential state ?

utilize alarm+pause Realization sleep function :

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <errno.h>

void catch_sigalrm(int signo)
{
    
	
}

unsigned int my_sleep(unsigned int seconds)
{
    
	int ret;
	struct sigaction act, oldact;

	act.sa_handler = catch_sigalrm;
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;

	//  register SIGALRM Processing function 
	ret = sigaction(SIGALRM, &act, &oldact);
	if (ret == -1)
	{
    
		perror("sigaction error");
		exit(EXIT_FAILURE);
	}

	//  Use alarm+pause Realization sleep function 
	alarm(seconds);
    // ----------- There may be a loss of CPU, Lead to SIGALRM It has been sent out , But below pause Not called yet 
	ret = pause();
	if (ret == -1 && errno == EINTR)
	{
    
		printf("pause sucess\n");
	}

	//  If other signals are captured during waiting , Then turn off the alarm clock , Ensure the robustness of the program .
	ret = alarm(0);

	//  recovery SIGALRM Default handler 
	sigaction(SIGALRM, &oldact, NULL);
	
    //  Return the waiting time of the alarm clock 
	return(seconds-ret);
}


int main()
{
    
	while(1) printf("---------sleep %u seconds-------\n", my_sleep(1));
	
	return 0;
}

In the above code, there is Time series and state The problem of . Imagine the following scenario :

Want to sleep , Set alarm clock 10 minute , hope 10 Minutes later, the alarm clock wakes itself up .

normal : timing , sleep ,10 Wake up by the alarm clock in minutes .

abnormal : When the alarm clock is set , Sleep 5 Wake up and go out to work in minutes ( Lose CPU),20 The work will be finished in minutes . Come back and go back to sleep , But the alarm clock has rung during labor (alarm Function has sent a signal ), Will not wake me up again .

3、 ... and 、 Timing problem analysis

Empathy , Review with the help of pause and alarm Realized my_sleep function . Imagine the following sequence :

  1. register SIGALRM Signal processing functions (sigaction...)
  2. call alarm(1) Function to set the alarm clock to 1 second .
  3. The function call has just ended , Start the countdown to 1 second . Lose the current process CPU, The kernel schedules processes with high priority ( There are many. ) Replace the current process . The current process cannot get CPU, Enter the ready state and wait CPU.
  4. 1 Seconds later , The alarm clock timed out , The kernel sends... To the current process SIGALRM The signal ( Natural timing , It has nothing to do with the state of the process ), The high priority process has not finished executing , The current process is still ready , The signal cannot be processed ( outstanding ).
  5. The high priority process has finished executing , The current process gets CPU resources , The kernel schedules the current process to execute .SIGALRM Signal delivery , Signal setting capture , Execute processing functions .
  6. The execution of the signal processing function ends , Returns the current process master process ,pause() Called pending wait .( Want to wait alarm Function sent SIGALRM The signal wakes itself up )
  7. can SIGALRM The signal has been processed ,pause Don't wait for the desired signal , So we'll wait together .

Four 、 Solve the timing problem :sigsuspend function

 shielding SIGALRM    //  So the signal can block 
alarm(seconds);
// ------------------ Lose CPU
 Unblock 
// ------------------ It may also be lost here CPU
ret = pause(); // Actively suspend , Equal signal 

   You can set the mask SIGALRM Method to control program execution logic , But set it anyway , Programs can be in Unblock the signal And Hang wait signal These two operating clearances are lost CPU resources . Unless these two steps are combined into one Atomic manipulation .sigsuspend Function has this function . It is used in occasions with strict timing requirements sigsuspend Replace pause.

#include <signal.h>

int sigsuspend(const sigset_t *mask); //  Hang wait signal .

/* RETURN VALUE sigsuspend() always returns -1, with errno set to inndicate the error (normally, EINTR). */

sigsuspend During a function call , The process signal mask word is determined by its parameters mask Appoint .

   A signal can be ( Such as SIGALRM) Shield words from temporary signals mask Delete in , So this is calling sigsuspend It will remove the shielding of the signal , Then hang up and wait . When sigsuspend return , The signal mask word of the process is restored to its original value . If the signal is shielded ,sigsuspend The signal is still masked after the function returns .


Improved version my_sleep:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>

void catch_sigalrm(int signo)
{
    
	
}

unsigned int my_sleep(unsigned int seconds)
{
    
	int ret;
	struct sigaction newact, oldact;
	sigset_t newmask, oldmask, suspendmask;
	unsigned int unslept;

	// 1、 by SIGALRM Set the snap function 
	newact.sa_handler = catch_sigalrm;
	sigemptyset(&newact.sa_mask);
	newact.sa_flags = 0;

	ret = sigaction(SIGALRM, &newact, &oldact);
	if (ret == -1)
	{
    
		perror("sigaction error");
		exit(EXIT_FAILURE);
	}

	// 2、 Set blocking signal set , Blocking SIGALRM The signal 
	sigemptyset(&newmask);
	sigaddset(&newmask, SIGALRM);
	sigprocmask(SIG_BLOCK, &newmask, &oldmask);

	// 3、 timing n second , Then we can produce SIGALRM The signal 
	alarm(seconds);

	// 4、 Construct a call sigsuspend Temporarily valid blocking signal set , Release right SIGALRM The block 
	suspendmask = oldmask;
	sigdelset(&suspendmask, SIGALRM);	//  Atomic manipulation 

	// 5、sigsuspend During call , Temporary blocking signal set is adopted suspendmask Replace the original blocking signal set 
	//  This signal set does not contain SIGALRMM The signal , Also suspend waiting ,
	//  such , Even before losing CPU, The alarm clock has been sent SIGALRM The signal , The signal will be blocked .
	// sigsuspend The call to... Was released SIGALRM The block , Will catch the signal , Restore program run .
	sigsuspend(&suspendmask);

	//  Get the remaining time of the last alarm clock 
	unslept = alarm(0);

	// 6、 recovery SIGALRM The original processing action , Echo the previous note 1
	//  When sigsuspend When awakened by the signal and returned , Restore the original blocking signal set .
	sigaction(SIGALRM, &oldact, NULL);

	// 7、 Release right SIGALRM The block , Echo the previous note 2
	sigprocmask(SIG_SETMASK, &oldmask, NULL);

	return(seconds-unslept);
}


int main()
{
    
	while(1) printf("---------sleep %u seconds-------\n", my_sleep(1));

	return 0;
}

5、 ... and 、 summary

The condition of the State , It is closely related to the system load , Reflects the unreliability of the signal . The more serious the system load , The more unreliable the signal is .

   Unreliability is caused by its implementation principle . The signal is realized by software ( Highly dependent on kernel scheduling , Strong delay ), After each system call , Or after interrupt processing , Need to scan PCB Pending signal set in , To determine whether to process a signal , When the system is overloaded , There will be timing confusion .

   This unexpected situation can only be in the process of writing the program , Anticipate ahead of time , Actively avoid , And not through GDB Program height and other means to make up for . And because the error is irregular , Later capture and reproduction is very difficult .

版权声明
本文为[baboon_ chen]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204210546350888.html