Linux下进程的总结(3)

进程的控制

1.进程的创建

fork()函数

在一个代码段中创建一个新的子进程可以使用fork()函数。

1.fork()函数以父进程为模板创建出了一个子进程,但是父子进程代码共享,数据独有一份。也就是分配新的内存块和内核数据结构。然后父进程的部分数据拷贝到了子进程。

2.fork()函数的返回值是pid > 0,子进程的返回值是 == 0的。

3.fork()创建出一个子进程后,到底是子进程先运行还是父进程先运行。这个优先级不确定。比如说子进程 和 父进程 在一个多核心的cpu的运行时候可能会并行执行。

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

int main()
{
pid_t pid;
printf("Before: pid = %d \n" ,getpid());
pid = fork();
printf("After The fork () pid = %d, return pid = %d \n", pid,getpid());
return 0;
}

在这里插入图片描述

分析以上代码可以知道在fork()函数之前pid是3196,执行fork()函数之后,子进程复制一份父进程的代码。但是子进程只运行,fork()后的代码段。第二行代码是父进程的代码结果。可以见得,fork()返回值是3197这是一个大于零的数。说明这是子进程返回的pid。第三行代码是子进程的代码段。可以见得,fork()返回值是0,说明这是该进程本身就是一个子进程。

特殊的vfork()函数

vfork()函数,子进程复制父进程的代码段。vfork()子进程和父进程共享地址空间,而fork()函数的子进程和父进程两份地址空间。

在这里插入图片描述

/* This is a programe for Vfork*/

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
printf("Firstly , The val is 100 \n");
int pid = vfork();
int val;
if(pid == 0)
{
 val = 200;
printf("This is child ! : pid = %d, getpid() :%d, val = %d \n", pid,getpid(),val);
exit(0);
}
else if (pid > 0)
{
printf("this is parent ! : pid = %d , getpid() = %d, val = %d \n ",pid,getpid(),val);
sleep(1);
}
return 0;
}

在这里插入图片描述

由以上代码可以得到,在子进程中修改了val的值,对于父进程来说它也被改变了。在子进程中val被赋值了200。在子进程结束的时候,父进程的val也被修改成了200。

vfork()创建过程

1.vfork也是创建一个子进程。子进程没有退出或者运行其他程序,父进程是阻塞的。也就意味着子进程先运行。子进程没有运行完成时,父进程暂时挂起。子进程退出之后父进程才能运行。##子进程不能在main()函数return 0 之后推出。

2.子进程先运行的原因是,创建出的子进程大多数的时候都是为了让它运行其他的程序。

3.父进程阻塞的原因,vfork创建出的子进程,父子进程是公用一块虚拟的内存空间的。

4.vfork设计出来的目的就是为了创建出一个子进程,然后直接运行其他的程序。而不是重新给子进程开辟新的空间,更新它自己的地址空间和页表。

自从fork函数更新了写实拷贝技术后,就被淘汰了。

2.进程的终止

当一个程序运行结束后需要退出了一般有3中退出的方式。

1.在main()函数当中使用return 0退出后程序结束。

2.exit(0)函数温和的退出程序。

3._exit(0)函数暴力退出程序。

退出程序会后的返回值表明了它的状态。如exit(int _status)表明状态。公有3种状态。

1.正常运行完毕,结果符合预期

2.正常运行完毕,但是结果不符合预期

3.异常退出,(如:段错误),根本就没有有return ,其返回标准不能当做评判标准。

在这里插入图片描述

现在我们通过程序来看一看 exit(0) 和 _exit(0)有什么不同?

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
printf("Hello ");
sleep(5);
printf("world!");
exit(0);
//_exit(0);
}

分别运行以上代码。得出以下结果

在这里插入图片描述

在这里插入图片描述
exit(0)会先把缓冲区的东西输出后,然后再让程序退出。
_exit(0)忽视缓冲区直接退出,不将缓冲区的东西打印出来。

3.进程的等待

一个进程退出之后,需要保存自己的退出原因,因此不会释放自己的所有资源。而父进程会等待着子进程的退出原因,然后结束自己的进程,释放自己的所有资源。而如果父进程始终不接收这个子进程的退出原因,那么子进程就会变成僵尸进程。造成内存泄漏,也是资源泄露。为了防止子进程变成僵尸进程,父进程就要关注并且管理子进程的退出状态。

父进程如何管理子进程的退出状态?

怎样关注子进程的退出状态?

在Linux下有一个wait()方法。

进程的等待就是等待子进程的状态改变,获取子进程的退出状态码,允许系统释放子进程的所有资源,这时候子进程的所有资源会释放掉。

进程等待能够有效地避免僵尸进程的产生。

使用 pid_t wait (int *status)
#include<unistd.h>
#include<errno.h>
#include<stdlib.h>
int main()
{
int pid = fork();
if(pid < 0)
{
exit(-1);
}

else if( pid == 0)

{
sleep (3);
exit(0);
}
//wait 函数的目的是为了等待任意一个子进程的退出
// 因为wait()是一个阻塞型的函数码,如果没有函数退出,他就一直等待,只到有子进程退出。如果wait(NULL)时则表明不关心退出状态。

pid_t id 
if((id = wait(NULL)) <0)
{
perror("wait error");
}
printf ("child %d , exit :%d \n " ,id,pid);
return 0;
}

使用 pid_t waitpid( pid _t pid,int *status,int options)

当这个函数正常返回的时候,就会收集到子进程的进程ID。如果设置了选项WNOHANG,而调试用的waitpid发现没有退出的子进程可以手机,则返回0。如果调用出错了,则返回-1,这时候errno会被设置成对应的值以指示错误所在

参数分析

pid :pid = -1等待任意一个子进程。此时与wait等效

pid > 0 表示等待的进程ID与pid相等的子进程

status :WIFEXITED(status):若为正常终止返回子进程返回状态,则为真。(查看进程是否正常退出)。
WEXITSTATUS(status):若WIFEXITED非零,提取子进程退出码(查看进程的退出码)。

options:
WNOHANG :若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正当结束则返回该子进程ID。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值