嵌入式LinuxC编程之进程控制(三)

进程等待是为了同步父进程与子进程,通常需要通过调用wait()等待函数是父进程等待子进程结束,如果父进程未调用等待函数,则子进程就会进入“僵尸”状态。
一、linux系统提供的等待函数原型如下:
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int *status)
pid_t waitpid(pid_t pid,int status,int options);
int waitid(idtype_t idtype,id_t id,siginfo_t *infop,int options);
二、wait()函数系统调用的工作过程:
    1、如果不存在子进程,即子进程创建失败,提示错误信息ECHILD,表示wait()系统调用的进程没有可以等待的进程。
2、如果存在进程:wait()函数系统调用中发送信号给子进程,可能会导致子进程结束运行。若发送的信号被子进程捕获,就会终止子进程的作用;若信号没有被子进程捕获到,则会是子进程非正常结束。此时参数status返回的状态值为接收到的信号值,存放在最后一个字节中。
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
//定义一个函数,用来判断是正常退出还是信号导致退出
void exit_s(int status)
{
	if(WIFEXITED(status))//
		printf("normal exit,status=%d\n",WEXITSTATUS(status));
	else if(WIFSIGNALED(status))
		printf("signal exit!status=%d\n",WTERMSIG(status));
}
int main(void)
{
	pid_t pid,pid1;
	int status;
	if((pid=fork())<0)//创建一个子进程
	{
		printf("child1 process error!\n");
		exit(0);
	}
	else if(pid==0)//如果是子进程
	{
	    //输出此时处于子进程中,输出其pid
		printf("the child1 process,pid=%d\n",getpid());
		exit(2);//退出子进程
	}
	if(wait(&status)!=pid)//如果是父进程,返回的pid不是子进程的,说明出现错误
	{
		printf("this is a parent1 process,pid=%d\nwait error!\n",getpid());
		exit(0);//退出父进程
	}
	else
	{
	   printf("this is a parent1 process,pid=%d\nwait success!\n",getpid());
	}
	exit_s(status);//返回此时子进程的退出方式
	if((pid=fork())<0)//再次创建子进程,这个创建还是在原来的父进程中
	{
		printf("child process error!\n");
		exit(0);
	}
	else if(pid==0)//如果是子进程
	{
		printf("the child2 process,pid=%d\n",getpid());
		pid1=getpid();
	//	kill(pid1,9);     //结束进程
	//	kill(pid1,17);    //进入父进程
	//	kill(pid1,19);    //终止进程
	}
	if(wait(&status)!=pid)
	{
		printf("this is a parent2 process,pid=%d\nwait error!\n",getpid());
		exit(0);
	}
	else
	{
	   printf("this is a parent2 process,pid=%d\nwait success!\n",getpid());
	}
	exit_s(status);
exit(0);
}
//**************************************
情况一:kill(pid1,9);表示只结束当前的二次创建的子进程
运行结果:
kill(pid1,9);
the child1 process,pid=2022
this is a parent1 process,pid=2021
wait success!
normal exit,status=2
the child2 process,pid=2023
this is a parent2 process,pid=2021
wait success!
signal exit!status=9  //返回9吧表示说,进程是收到信号,有kill函数发出的。
//之后wait函数也发送信号,但是子进程未收到,说明子进程已经非正常结束
//**************************************
//**************************************
情况二:kill(pid1,17);进入父进程
运行结果:
kill(pid1,17);
the child1 process,pid=2045
this is a parent1 process,pid=2044
wait success!
normal exit,status=2
the child2 process,pid=2046
this is a parent2 process,pid=2044
wait success!
normal exit!status=0  //表示进程结束了
//**************************************
情况三:kill(pid1,19);进入父进程
运行结果:
kill(pid1,19);
the child1 process,pid=2070
this is a parent1 process,pid=2059
wait success!
normal exit,status=2
the child2 process,pid=2071
|
//**************************************
三、关于exit_s调用的宏定义
1、WIFEXITED(status):该宏定义的作用是当子进程正常退出,返回真值。正常退出是指系统通过调用exit()和_exit()在main()函数中返回
2、WIFSIGNALED(status):表示子进程被没有捕获的信号终止时,返回真值。
3、WIFSTOPPED(status):当子进程接收到停止信号时,返回真值。这种情况仅出现在调用waitpid()函数时使用了WUNTRACED选项
4、WIFCONTINUED(status):该宏定义表示当子进程接收到信号SIGCONT时,继续运行。
5、WEXITTSTATUS(status):返回子进程正常退出时的状态,该宏定义只适用于当WIFEXITED为真值时
6、WTERMSIG(status):用于子进程被信号终止的情况,返回此信号类型,该宏定义用于WIFSIGNALED真值时
7、WSTOPSIG(status):返回使子进程停止的信号类型,该宏用于WIFSTOPPED为真值时。
四、另一函数waitpid():
1、与wait()函数主要区别是:wait()函数用于等待所有子进程结束,而waitpid()仅用于等待某个特定子进程结束,这个特定的进程是指其pid与函数中的参数pid相关时。
  以下几种情况:
      ① pid<-1 :等待进程组ID等于pid绝对值的任一进程时退出。
  ② pid=-1 :等待任意一子进程退出
  ③ pid=0  :等待进程组ID等于调用进程的组ID的任一进程时退出
  ④ pid>0  :等待进程ID等于pid的子进程退出。
2、参数options的取值及其意义如下:
  WNOHANG:该参数表示没有子进程退出就立即返回;
  WUNTRACED:该参数表示若发现子进程处于“僵尸”状态但未报告状态,则立即返回。
五、进程结束
1、当想要终止或结束一个进程时,会使用系统调用exit()函数正常退出进程。该系统调用包括exit()和_exit()两个函数
2、exit()函数:在终端输入“man 3 exit”命令,可以显示exit()函数的原型及其功能等信息,其作用是终止进程,并将运算status&0377表达式后的值返回给父进程,在父进程中用wait()函数获取该值。
3、_exit()函数:与exit()函数功能类似,当然它们有区别;
4、区别:我们知道vfork()函数,只能调用_exit()函数退出子进程,因为调用exit()函数时,对输入输出流进行刷新,释放占用的资源以及清空缓冲区等;而_exit()函数不存在此功能。
六、多个进程间的关系
1、进程组ID:进程组有一个特殊的进程,该进程的ID与进程组的ID相同。调用pid_t getpgpid(void)函数可返回该函数所在的进程组ID。
2、进程组的生命周期是从该进程组的创建到最后一个进程终止;

3、linux系统中可以调用setpgid(pid_t pid,pid_t pgid)函数创建一个新的进程组或者将一个进程加入到进程组中。两种情况:① 当进程pid和pgid两值相等,该函数功能是创建一个新的进程组;② 如果两个值不同,并且pgid是一个已存在的进程组,那么就将pid进程加入到pgid这个进程中。

#include<sys/types.h>
#include<unistd.h>
#include<stdio.h>
int main(void)
{
	int a;
	pid_t pgid,pid;
	pid=(long)getpid();//获得本进的pid
	pgid=(long)getpgrp();//获得本进程组的pid
	a=setpgid(pid,pgid);//创建一个新的进程组
	printf("a=%d,pid=%ld,pgid=%ld\n",a,pid,pgid);
	return 0;
}
//结果:a=0,pid=4463,pid=4463

七、时间片分配
1、时间片轮转调度策略
2、优先权调度策略
 ① 非抢占式优先权策略
 ② 抢占式优先权策略


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值