Linux-信号

信号

掌握知识点:
在这里插入图片描述

- 1.信号

1>信号的概念
共性:1简单;2不能携带大量信息(比如:不能携带结构体);3满足某个条件才发送.
2>每个信号都是内核处理在这里插入图片描述
在这里插入图片描述3>信号的两种状态:1.递达;2.未决(阻塞(屏蔽)造成的)
在这里插入图片描述

在这里插入图片描述4>信号处理的三种方式:1执行默认动作;2忽略(丢弃)(不是不处理,是处理方式是丢弃.);3捕捉(不执行默认动作,调用用户定义的函数)
5>信号四要素:1编号,2名称;3事件;4默认处理 ;其中默认处理包括下图五项:
在这里插入图片描述
man 7 signal //查看man文档,如果编号有三个的事件linux系统取中间值.(linux信号一览表:https://blog.youkuaiyun.com/KHY666/article/details/109674411注意:9-SIGKILL和19-SIGSTOP不允许忽略和捕捉.(保护系统的作用))

2.产生信号

1>按键产生
在这里插入图片描述
2>硬件异常产生的信号
在这里插入图片描述
3>函数\命令产生的信号(kill,arise,abort)
kill命令:eg:kill - PID //kill不一定就会杀死对应的进程,作用效果是对应的信号决定的.
kill()函数:

	/*******************************************************
	*函数:kill() 
	*头文件: #include <sys/types.h> #include <signal.h>
	*格式:   int kill(pid_t pid, int sig);//pid_t pid:pid>0(发送信号给指定进程);pid=0(发送信号给调用kill函数的同组所有进程);pid<0(取|pid|发送给对应进程组)等同:kill -signal -pid(组pid);pid=-1(发送有权限的所有进程);int sig:对应的信号.
	*作用:产生信号
	*返回值: On success (at least one signal was sent), zero is returned.  On error,-1 is returned, and errno is set appropriately.
	********************************************************/


PPID:父进程ID; PGID:组ID; UID:用户ID;SID:会话ID

raise()函数:给自己发送指定信号; //arise(SIGSEGV)=kill(getpid(),SIGSEGV);
abort()函数:给自己发异常终止信号SIGABRT;// void abort(void);
4>软件条件产生信号(定时的方法)
1>>每个进程都有且仅有一个定时器
2>>alarm()函数

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdio.h>
#include <unistd.h>
#include<stdlib.h>


int main(int argc,char* argv[])
{
	if(argc<2)
	{
		printf("please cin ./b.c' filename");
	}
	/*******************************************************
	*函数:alarm() 
	*头文件: #include <unistd.h> 
	*格式: unsigned int alarm(unsigned int seconds);// unsigned int seconds:指定定时的时间(s)
	*作用:设定闹钟,到达时间后,内核会向给当前进程发送14(SIGALRM)信号.当前进程:默认动作终止(进程退出). //alarm(0)
	*返回值:返回上一次调用alarm()函数的剩余时间,若没有调用就返回0.无失败返回值.
	********************************************************/
	alarm(1);//调用alarm()函数;设置闹钟
	for(int i=0;;i++)
	printf("%d\n",i);//输出到屏幕
	return 0;
}

使用time命令查看程序运行时间(实际执行时间=用户时间+系统时间+等待时间)
在这里插入图片描述
这是直接输出到屏幕

在这里插入图片描述
这是使用重定向符输出到out文件后,用户时间+系统时间几乎等于程序运行的实时时间
因此程序优化首选I\O
3>>setitimer()函数(可用于定时任务)

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdio.h>
#include <unistd.h>
#include<stdlib.h>
#include <sys/time.h>
#include <signal.h>

/*********************************************用户自定义的handler()函数*******************************************/
void function(int sig )
{
	printf("*********\n");
}
/*******************************************************实现alarm()函数************************************************
unsigned int set_alarm(unsigned int sec)
{
	
	struct itimerval value,retval;
	int ret;
	value.it_value.tv_sec=sec;
	value.it_value.tv_usec=0;
	value.it_interval.tv_sec=0;
	value.it_interval.tv_usec=0;
	/*******************************************************
	*函数:setitimer() 
	*头文件: #include <sys/time.h>
	*格式: int setitimer(int which, const struct itimerval *new_value,struct itimerval *old_value);
	//int which:指定定时方式(
	1.自然定时-ITIMER_REAL,对应信号14(SIGALARM);
	2.虚拟空间计时(用户空间)(进程占用cpu的时间)-ITIMER_virtual,对应信号26(SIGVTALARM);
	3.运行时计时(用户+内核)(进程占用cpu和系统调用的时间)-ITIMER_PROF,对应信号27(SIGPROF)); 
	const struct itimerval *new_value:定时的时长(传入参数);struct itimerval *old_value:上次定时的剩余时间(传出参数)
	*struct itimerval {
     	*	struct timeval it_interval; //设定与第一次定时时长的间隔值(若等于零,就定时一次,若不等于零,则间隔时间为it_interval的值,且无限次)
     	*	struct timeval it_value;    //设定第一次定时时长
 	*	};
	*
 	*	struct timeval {
    	*	 time_t      tv_sec;         //seconds 
  	*	   suseconds_t tv_usec;        // microseconds 
 	*	};//结构体不用创建,包含在头文件里
	*作用:设定闹钟(us级),到达时间后,内核会向给当前进程发送对应信号(int which).当前进程执行默认动作.
	*返回值:0-成功;-1-失败;
	*********************************************************
	ret=setitimer(ITIMER_REAL,&value,&retval);
	if(ret==-1)
	{
		perror("setitimer error");
		exit(1);
	}
	return retval.it_value.tv_sec;
}
*********************************************************************************************************************/

	
int main(int argc,char* argv[])
{
	if(argc<3)
	{
		printf("please cin ./b.c' filename\n");
		exit(1);//退出进程,不然会报段错误.
	}
	struct itimerval value,retval;
	value.it_value.tv_sec=atoi(argv[1]);  //第一次时钟argv[1]s
	value.it_value.tv_usec=0;
 
	value.it_interval.tv_sec=atoi(argv[2]);  //每间隔时间argv[2]s激发一次时钟
	value.it_interval.tv_usec=0;
/*******************************************************
*函数:signal() 
*头文件:  #include <signal.h>
*格式: sighandler_t signal(int signum, sighandler_t handler); //int signum:需要捕捉的信号名称(号);sighandler_t handler:执行用户自己的动作(handler函数),而不执行默认动作;
*    // handler函数: typedef void (*sighandler_t)(int); //函数指针,传入参数为int 返回为void类型的函数
*作用:捕捉指定的信号.
*返回值:signal()  returns  the previous value of the signal handler, or SIG_ERR on error.  In the event of an error,  errno  is  set  to  indicate  the cause.
********************************************************/
	signal(SIGALRM,function);//注册SIGALRM信号的捕捉处理函数
	int ret=setitimer(ITIMER_REAL,&value,&retval);//自然定时-ITIMER_REAL,对应信号14(SIGLARM);
	if(ret==-1)
	{
		perror("setitimer error");
		exit(1);
	}
while(1);//防止进程比时钟提前结束
	return 0;
}

3.信号集操作函数

操作对象:
在这里插入图片描述我们自己在程序中定义一个信号(set)集合来改变系统阻塞信号集合,(阻塞信号集又会影响未决信号集)已达到屏蔽指定信号的目的.

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

/*******************************************************
*
*使用信号操作集函数,实现屏蔽指定的信号,并将未决信号集对应的信号打印出来
*
********************************************************/
int main(void)
{

	//读文件
	/*******************************************************
	*函数1-5:操作用户自定义信号集函数//linux系统变成不能使用按位或的思想控制对应的信号屏蔽字,必须使用对应的函数. 
	*头文件:#include <signal.h>
	*格式: //sigset_t set 用户先自己定义一个信号集合,用下面的函数设置对应的信号屏蔽字 ,sigset_t// typedef unsigned long sigset_t
	   int sigemptyset(sigset_t *set);				//作用:将用户的信号集清零(一共64个信号,全部清零);返回值:成功-0,失败--1;

       int sigfillset(sigset_t *set);				//作用:将用户的信号集置一(一共64个信号,全部清零);返回值:成功-0,失败--1;

       int sigaddset(sigset_t *set, int signum);	//作用:将某个信号加入信号集(64个信号中选择,一般写大写字母,不写编号(不同系统));返回值:成功-0,失败--1;

       int sigdelset(sigset_t *set, int signum);	//作用:将某个信号清出信号集(64个信号中选择,一般写大写字母,不写编号(不同系统));返回值:成功-0,失败--1;

       int sigismember(const sigset_t *set, int signum);//作用:查看某个信号是否在信号集中;返回值:在-1,不在-0,失败--1;
	*函数6: sigprocmask()函数
	*头文件:#include <signal.h>
	*格式:  int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);//
	how三个取值:
			SIG_BLOCK-屏蔽用户自己定义的信号集的对应信号;
			SIG_UNBLOCK-解除屏蔽用户自己定义的信号集的对应信号;
			SIG_SETMASK-将用户自己定义的信号集合替换系统的阻塞信号集(谨慎使用);
	const sigset_t *set:传入参数,用户自己定义的信号集;
	sigset_t *oldset:传出参数,保存修改屏蔽字之前的阻塞信号集(不保存就传NULL);
	*作用:实现指定信号的屏蔽或解除;前面信号集操作函数设置好了对应的要操作信号,通过sigprocmask()函数结合用户自己创建的信号机对系统阻塞信号集的屏蔽字进行修改,进而实现指定信号的屏蔽或解除
	*返回值:成功-0,失败--1;
	函数7: sigpending()函数
	*头文件:#include <signal.h>
	*格式:  int sigpending(sigset_t *set1);//sigset_t *set:传出参数,当前进程的未决信号集(需要创建set1(sigset_t set1)来接收).
	*作用:读取当前进程的未决信号集.(//sigprocmask()函数操作阻塞信号集,sigpending()函数读取未决信号集间接的推出阻塞信号集的状态)
	*返回值:成功-0,失败--1;
	********************************************************/
	//创建信号集

	//sigset_t myset, oldset, pendset;//myset-自定义信号集合,(使用指定的数据类型);oldset-sigprocmask()函数记录使用;pendset-sigpending()函数读取未决信号使用
	sigset_t myset,oldset,pendset;
	//指定要屏蔽的信号
	sigemptyset(&myset);//先清零
	sigaddset(&myset,SIGTSTP);//加入要屏蔽或则解除屏蔽的信号(eg:SIGTSTP)
	if(sigaddset(&myset,SIGQUIT)==-1)//加入要屏蔽或则解除屏蔽的信号(eg:SIGQUIT)
	{
		perror("sigaddset error");
		exit(1);
	}
	sigprocmask(SIG_BLOCK,&myset,NULL);//使用自己定义的myset信号集操作阻塞信号集,对应的信号来了之后就会阻塞.
	
	while(1)
	{
		sigpending(&pendset);//读取当前进程的未决信号保存在pendset里面
		//打印出pendset信号集的屏蔽字(使用的sigismember()函数判断)
		for(int i=0;i<31;i++)
		{
			if(sigismember(&pendset,i)==1)
			{
				putchar('1');
			}
			else{
			putchar('0');
			}
			
		}
		printf("\n");
		sleep(1);
	}
	
	return 0;
}
// 编译报错:error: stray ‘\200’ in program;原因:中文字符引起(cat -A filename查看,乱码的地方就是中文)

运行结果:
在这里插入图片描述

4.信号捕捉

1>signal()函数

/*******************************************************
*函数:signal() 
*头文件:#include <signal.h>
*格式: sighandler_t signal(int signum, sighandler_t handler); //int signum:需要捕捉的信号名称(号);sighandler_t handler:执行用户自己的动作(handler函数),而不执行默认动作;sighandler_t: 返回SIG_ERR为错误(sighandler_t hander;  if(hander==SIG_ERR) perror("");...)
*    // handler函数: typedef void (*sighandler_t)(int); //函数指针,传入参数为int 返回为void类型的函数
*作用:捕捉指定的信号.
*返回值:signal()  returns  the previous value of the signal handler, or SIG_ERR on error.  In the event of an error,  errno  is  set  to  indicate  the cause.
********************************************************/

2>sigaction()函数

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdio.h>
#include <unistd.h>
#include<stdlib.h>
#include <sys/time.h>
#include <signal.h>


void docatch (int signo)
{
	printf("--------catch SIGTSTP---------\n ");
	sleep(5);//验证(如果在屏蔽期间本信号来了多次,解除屏蔽后只执行一次(再多次按ctrl+z)最后也只执行一次)
}
	
int main()
{
	struct sigaction act;
	//struct sigaction 结构体配置
	act.sa_flags=0;
	act.sa_handler=docatch;
	sigemptyset(&act.sa_mask);//清空act.sa_mask信号集
/******************************************************************************************************************
	*函数:sigaction() 
	*头文件: #include <signal.h>
	*格式: int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
	*struct sigaction 
		{
		       void     (*sa_handler)(int);		//函数指针,用户自己的动作函数,也可传入SIG_IGN表忽略,SIG_DFL表执行默认动作
		       void     (*sa_sigaction)(int, siginfo_t *, void *);//信号传递信息时用,且sa_flags=SA_SIGINFO,不能传零.
		       sigset_t   sa_mask;			//sigaction()函数在执行捕捉信号时,用户指定信号屏蔽集,此时sa_mask信号集会替代系统的阻塞信号集,直到信号捕捉截止后恢复系统阻塞信号集;
		       int        sa_flags;			//sa_flags=0时,默认参数,在捕捉函数执行期间,不管sa_mask指定与否,自动屏蔽已经被捕捉的信号,及本信号(sa_handler函数运行期间有效).
		       (如果在屏蔽期间信号来了多次,解除屏蔽后只执行一次)(中断系统调用,函数是否重启也是由该参数设置:见下图)
		       void     (*sa_restorer)(void);		//没作用了
               };//结构体不用创建,包含在头文件里
	*作用:修改信号处理函数,注册一个信号捕捉函数(相当于signal()函数)
	*返回值:0-成功;-1-失败;
	总结:
	1.进程正常运行时,默认PCB中有一个信号屏蔽字,假定为☆,它决定了进程自动屏蔽哪些信号。当注册了某个信号捕捉函数,
	捕捉到该信号以后,要调用该函数。而该函数有可能执行很长时间,在这期间所屏蔽的信号不由☆来指定。而是用sa_mask 来
	指定。调用完信号处理函数,再恢复为☆。
	2.XXX信号捕捉函数执行期间,xXX信号自动被屏蔽。
	3.阻塞的常规信号不支持排队,产生多次只记录一次。(后32个实时信号支持排队)
*********************************************************************************************************************/
	sigaddset(&act.sa_mask,SIGQUIT);//在执行捕捉函数时屏蔽SIGQUIT信号,函数执行完之后执行.
	int ret=sigaction(SIGTSTP,&act,NULL);
	if(ret==-1)
	{
		perror("sigaction error");
		exit(1);
	}
	while(1);
	return 0;
}

在这里插入图片描述
3>中断系统调用(慢速系统调用):例如像pause()函数,在执行时可能永久阻塞,当有信号来传来时,可能打断阻塞,这时就需要根据情况需要,设置sa_flags来设置.

4>内核实现信号捕捉的过程
在这里插入图片描述5>信号捕捉的特性
在这里插入图片描述

5.竞态条件(时序竞态)

1>puase()函数(要求不高的情况使用(存在时序竞态的问题-进一步说明软信号不可靠))

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

void myfunction(int signo)
{;}
unsigned int mysleep(unsigned int seconds)
{
	struct sigaction act, oidact;
	
	act.sa_handler=myfunction;
	sigemptyset(&act.sa_mask);
	act.sa_flags=0;
	
	sigaction(SIGALRM,&act,&oidact);//注册捕捉SIGALRM信号函数,执行自定义的函数,防止SIGALRM信号杀死进程;
	alarm(seconds);
	/*******************************************************
	*函数:pause() 
	*头文件: #include <unistd.h>
	*格式: int pause(void);
	*作用:将调用该函数的进程处于挂起状态,直到有信号将它唤醒(信号默认是忽略不能唤醒,信号是默认是结束进程,则该进程直接杀死,退出挂起状态.若信号是捕捉,并不是杀死进程,则可以唤醒)
	*返回值: returns  only when a signal was caught and the signal-catching function returned.  In this case, pause() returns -1, and errno is  set to EINTR.(注意成功的返回值是-1,errno为EINTR)
	********************************************************/
	//若此处该进程可能失去cpu,前面调用了alarm()函数,此时计数在内核,失去cpu不影响计数,此时alarm()时间到后,发送sigalrm信号,
	//当此进再次得到cpu时,内核首先处理信号,再进入用户态调用pause()函数,(alarm()函数只是计时,程序不会阻塞,pause()函数会阻塞不会计时),此时没有信号
	//发送给当前进程了,所以会造成程序一直阻塞.这就是时序竞态的问题
	int ret=pause();
	if(ret == -1 )//必须写
	{
		printf("pause success.\n");
	}
	int temp=alarm(0); //防止没有延时到指定时间接收到信号
	sigaction(SIGALRM,&oidact,NULL);//恢复现场.
	return temp;
}
/*********************************************
*使用pause()和alarm()函数实现sleep()函数
*********************************************/
int main(int argc,char * argv[])
{
	if(argc<2)
	{
		printf("输入参数错误\n");
		exit(1);
	}
	while (1){
	mysleep(atoi(argv[1]));//argv[1]延时时间
	printf("success delay %ds,  ",atoi(argv[1]));
	}
	return 0;
}


2>sigsuspend()函数(解决时序竞态的问题)

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

void myfunction(int signo)
{;}

unsigned int mysleep(unsigned int seconds)
{
	struct sigaction act, oldact;
	sigset_t newmask,oldmask,suspmask;
	//1.注册捕捉SIGALRM信号函数,执行自定义的函数,防止SIGALRM信号杀死进程;
	act.sa_handler=myfunction;
	sigemptyset(&act.sa_mask);
	act.sa_flags=0;
	sigaction(SIGALRM,&act,&oldact);
	//2.设置阻塞信号集
	sigemptyset(&newmask);
	sigaddset(&newmask,SIGALRM);
	sigprocmask(SIG_BLOCK,&newmask,&oldmask);//操作阻塞信号集,将SIGALRM信号屏蔽,保证后续调用alarm()函数时不会接收SIGALRM信号
	//3.定时n秒,到时后可以产生SIGALRM信号
	alarm(seconds);
	//4.创建一个sigsuspend()函数临时有效的阻塞信号集代替系统阻塞信号集,并且在临时信号集里要解除SIGALRM信号的屏蔽
	suspmask=oldmask;//此时临时有效的阻塞信号集的SIGALRM信号没有被屏蔽
	sigdelset(&suspmask,SIGALRM); //保证SIGALRM信号没有被屏蔽
	//5.调用sigsuspend()函数
	/*******************************************************
	*函数:sigsuspend() 
	*头文件: #include <signal.h>
	*格式: int sigsuspend(const sigset_t *mask);
	*作用:将调用该函数的进程处于挂起状态,直到有信号将它唤醒(信号默认是忽略不能唤醒,信号是默认是结束进程,则该进程直接杀死,退出挂起状态.若信号是捕捉,并不是杀死进程,则可以唤醒)且该函数调用期间系统阻塞信号集由参数const sigset_t *mask替换,直到函数调用完毕.原子操作(不可再细分的函数,可将信号解除屏蔽与进程挂起连起来,这段时间进程不会失去cpu)
	*返回值: sigsuspend() always returns -1, with errno set to  indicate  the  error(normally, EINTR)(注意成功的返回值是-1,errno为EINTR)
	********************************************************/
	
	int ret1=sigsuspend(&suspmask);  //原子操作.(不可再细分的函数,可将信号解除屏蔽与进程挂起连起来,这段时间进程不会失去cpu)此函数一调用,系统的阻塞屏蔽集就会被suspmask信号集替代,进而保证同时性,及解决了时序竞态的问题
	if(ret1==-1)//必须写
	{
		printf("sigsuspend succes\n");
	}
	int temp=alarm(0); //防止没有延时到指定时间接收到信号
	//6.恢复SIGALRM,呼应1
	sigaction(SIGALRM,&oldact,NULL);//恢复现场.
	//7.解除SIGALRM的阻塞,呼应2
	sigprocmask(SIG_SETMASK,&oldmask,NULL);
	return temp;
}

/*********************************************
*
*使用sigsuspend()函数实现sleep()函数(解决puase()函数的时序静态的问题)
*
*********************************************/
int main(int argc,char * argv[])
{
	if(argc<2)
	{
		printf("输入参数错误\n");
		exit(1);
	}
	while (1){
	mysleep(1);//argv[1]延时时间
	printf("success delay %ds,  ",atoi(argv[1]));
	}
	return 0;
}


6.全局变量异步I/O

由于内核与进程同事操作全局变量,导致全局变量异步I/O的问题

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

intn=0,flag=0; //全局变量

void  sys_err(char*   str) 
{ 
	perror(str); 
	exit(1); 
} 
void do_sig_child(int	num) 
{
	printf("I	am	child %d\t%d\n",getpid(),n);
	n+=2;
	flag=1; 
   sleep(1);  
} 
void do_sig_parent(int	num)
{
	 printf("I	am	parent%d\t%d\n",getpid(),n);
	 n+=2;
	 flag=1;
	 sleep(1); 
} 
//创建两个进程,实现父子进程交替数数;
int	main(void) 
{
pid_tpid;
struct	sigaction	act;
if((pid=fork())<0)
sys_err("fork");
else if(pid>0)
{
 	n=1;
	sleep(1);
	act.sa_handler	=	do_sig_parent; 
	sigemptyset(&act.sa_mask); 
	act.sa_flags=0;
	sigaction(SIGUSR2,&act,NULL); //注册自己的信号捕捉函数 父使用 SIGUSR2 信号 do_sig_parent(0); 
	while(1)
	{ 
		/*waitforsignal*/;
		if(flag==1)
		 	{ 
			 //父进程数数完成 
			  kill(pid,SIGUSR1);//若此时父进程失去cpu,子进程的到cpu,并开始数数,
			  //数完数后发送信号给父进程,父进程得到cpu,内核首先处理子进程的信号并开始数数.
			  //然后开始执行flag=0,此时flag=0,将不会再发送信号.就存在全局变量异步I/O的问题(删除父子进程的sleep()函数).
			  flag=0; //标志已经给子进程发送完信号 
			} 
	} 
}
else if(pid==0)
{ 
	n=2;
	act.sa_handler	=	do_sig_child; 
	sigemptyset(&act.sa_mask); 
    act.sa_flags=0; 
	sigaction(SIGUSR1,&act,NULL);
	while(1)
	{ 
		/*waitingforasignal*/;
		 if	(flag==1){
			kill(getppid(),SIGUSR2); flag=0; 
		} 
	}
}
	return0; 
}

解决此问题:1>尽量使用局部变量;2>使用线程锁;3>上述问题虽然可以通过sleep函数来解决,但是sleep函数会导致数数效率太低,可以取消全局变量flag,让发送信号的操作在用户处理函数中完成即可。

7.可重入函数\不可重入函数

在这里插入图片描述

8.利用SIGCHLD信号回收子进程

#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include<unistd.h>
void child_hander(int signo)
{
	int status;
	pid_t pid;
	if(pid=waitpid(0,&status,WNOHANG)>0) //如果有多个子进程需要回收,一定要使用while(),可以防止多个子进程同时死亡
     
      if (WIFEXITED(status)) {
       printf("child exited, status=%d\n", WEXITSTATUS(status));
   } else if (WIFSIGNALED(status)) {
       printf("killed by signal %d\n", WTERMSIG(status));
   }
}
/************************************
*子进程结束后会向父进程发送SIGCHLD信号,父进程利用SIGCHLD信号回收子进程
************************************/
int main()
{
	pid_t pid;
	pid=fork();
	if(pid==-1)
	{
		perror("fork error");
		exit(1);
	}
	//父进程利用SIGCHLD信号回收子进程
	if(pid>0)
	{
		//注册SIGCHLD信号捕捉函数
		struct sigaction act;
		act.sa_handler=child_hander;
		sigemptyset(&act.sa_mask);
		act.sa_flags=0;
		sigaction(SIGCHLD,&act,NULL);
		while(1);//等待回收子进程
	}
	if(pid==0)
	{	sleep(1);//保证SIGCHLD信号捕捉函数被注册
		execlp("ls","ls","-l",NULL);//execlp()函数没有返回值,对于此类子进程借用信号进行回收.
	}
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值