一、进程相关概念
狭义定义:进程就是一段程序的执行过程。
广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。通俗来讲,进程就是跑起来的程序 (程序是静态的概念)。
Linux下查看程序:
ps -aux 查看相关进程 ps查看指令 top指令 类似windows 的任务管理器
ps -aux|grep (进程名) 过滤多余进程 ,查看自己想要的进程。 eg:ps -aux|grep init
进程标识符(pid)
系统给每个进程定义了一个唯一标识该进程的非负正数,称作进程标识符。进程标识符可以简单的表示为主进程表中的一个索引,类似身份证。
Pid=0:称为交换进程 --进程调度
Pid=1:init进程 --系统初始化
父子进程
在 进程A基础上创建进程B,A为父进程,B为子进程。
进程地址空间分布
二、进程相关API
fork函数创建进程
函数原型
返回值
调用成功,即成功创建了一个子进程,被调用一次,能够返回两次:返回值为0:代表当前进程是子进程;返回值为非负数:代表当前进程为父进程;调用失败,返回-1;
2、获取进程pid(getpid函数)
函数原型(调用后返回当前进程pid)
相关代码实现
include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid;//定义一个pid号
pid=getpid();//获取当前进程pid号
printf("before fork:pid=%d\n",pid);
fork();//创建进程
pid_t pid2;
pid2=getpid();//获取创建后进程pid号
printf("after fork:pid2=%d\n",pid2);
if(pid == pid2){
printf("This is father print\n");
}else{
printf("This is child print,child pid=%d\n",getpid());
}
return 0;
}
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid;
int data=10;
printf("father id:%d\n",getpid());
pid=fork();
if(pid > 0){
printf("This is father print,father pid=%d\n",getpid());
}else if(pid == 0){
printf("This is child print,child pid=%d\n",getpid());
data=data+10;
}
printf("data=%d\n",data);
return 0;
}
编译结果
3.vfork函数
函数原型
vfork函数大部分和fork函数一样,主要有以下两点不同:
1.vfork直接使用父进程存储空间,不拷贝,fork会将父进程进行全拷贝;
2.vfork保证子进程先运行,当子进程调用exit退出后,父进程才执行;
代码实现
include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int cnt = 0;
pid= vfork();
if(pid > 0){
while(1){
printf("This is father print,pid=%d\n",getpid());
sleep(1);
printf("cnt=%d\n",cnt);
}
}
else if(pid == 0){
while(1){
printf("This is child print,child pid=%d\n",getpid());
sleep(1);
cnt++;
if(cnt == 3){
exit(0);
}
}
}
return 0;
}
三、等待子进程退出
僵尸进程:僵尸进程是当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。如果父进程先退出 ,子进程被init接管,子进程退出后init会回收其占用的相关资源。
孤儿进程:孤儿进程是没有父进程的进程,孤儿进程这个重任就落到了init进程身上,init进程就好像是一个民政局,专门负责处理孤儿进程的善后工作。
wait函数和waitpid函数(等待子进程退出)
函数原型
从本质上讲,系统调用waitpid和wait的作用是完全相同的,但waitpid多出了两个可由用户控制的参数pid和options,从而为我们编程提供了另一种更灵活的方式。两者区别之一:wait函数会阻塞父进程,waitpid函数有个选项可以选择不阻塞;
参数pid:进程pid号
参数options:options提供了一些额外的选项来控制waitpid,目前在Linux中只支持WNOHANG和WUNTRACED两个选项,这是两个常数,可以用"|"运算符把它们连接起来使用。
参数status:非空时表示子进程退出状态放在它所指向的地址中。
代码实现
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int cnt = 0;
int status=10;
pid= fork();
if(pid > 0){
// pid_t wait(int *status);
wait(&status);
printf("child quit,child status=%d\n",WEXITSTATUS(status));
while(1){
printf("This is father print,pid=%d\n",getpid());
sleep(1);
printf("cnt=%d\n",cnt);
}
}
else if(pid == 0){
while(1){
printf("This is child print,child pid=%d\n",getpid());
sleep(1);
cnt++;
if(cnt == 3){
exit(3);
}
}
}
return 0;
}
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int cnt = 0;
int status=10;
pid= fork();
if(pid > 0){
// pid_t wait(int *status);
// pid_t waitpid(pid_t pid, int *status, int options);
// wait(&status);
waitpid(pid,&status,WNOHANG);
printf("child quit,child status=%d\n",WEXITSTATUS(status));
while(1){
printf("This is father print,pid=%d\n",getpid());
sleep(1);
printf("cnt=%d\n",cnt);
}
}
else if(pid == 0){
while(1){
printf("This is child print,child pid=%d\n",getpid());
sleep(1);
cnt++;
if(cnt == 3){
exit(3);
}
}
}
return 0;
}