用户->外壳程序(shell,lib)->系统调用->操作系统->驱动->底层的软硬件
系统调用实际上是操作系统对外提供的接口
进程与普通程序的差别
在Linux下一切皆文件,程序也就是一些二进制文件,开始是在硬盘上存放的的。
//如果我们将这个程序跑起来,那么这个程序得加载到内存中成为可执行程序。
进程与普通程序的区别:进程具有PCB(进程控制块)她是用来描述进程信息的
进程是一个实体,每个进程都有它独有的地址空间(这块地址空间是虚拟内存)并非物理内存
如果要管理内存中的多个应用程序(进程)
1、必须需要每个进程的PCB信息(进程的描述信息)
2、必须将所有进程的PCB信息连接起来(组织)
因此操作系统对进程进行管理实际上是通过这些进程信息的结构进行管理(task_struct)
创建子进程使用fork()函数。
我们直到在命令行运行一个命令或者程序都会产生一个bash的子进程去完成。
int main()
{
pid_t id=fork();
if(id<0)
{
perror("fork");
}
else if(id==0)
{
printf("children:%d,%d",getpid(),getppid());
}
else
{
printf("father:%d,%d\n",getpid(),getppid());
usleep(1000);
}
return 0;
}
在程序运行完成之后我们可以查看打印的进程编号PID
从这里我们可以看出我们在命令行运行程序的时候其实是通过创造子进程的方式去运行的
我们在shell的子进程的里有创建了一个子进程这个子进程的使用getpid()去获取当前进程的pid编号,使用getppid()去获取当前进程的父进程的pid编号
因此通过途中的紫色部分我们就可以看书自己创建的父进程的pid编号是shell的子进程的编号。
如果去掉usleep再次验证这个程序:
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t id=fork();
if(id<0)
{
perror("fork");
}
else if(id==0) //起分支作用进入自己创建的子进程
{
printf("children:%d,%d",getpid(),getppid());
}
else //进入shell的子进程也就是自己创建的子进程的父进程
{
printf("father:%d,%d\n",getpid(),getppid());
}
return 0;
}
为什么此时自己创建的子进程的父进程的pid变成了1?
因为此时父进程并没有等待子进程
那么父进程运行完成之后,已经没了
此时的子进程变成了孤儿进程,因此孤儿进程的父进程的pid使用1去替代
我们都知道父子进程的代码是共享的,数据是自己私有的。
如果我们那对这个程序再次进行修改:
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t id=fork();
if(id<0)
{
perror("fork");
}
else if(id==0)
{
printf("children:%d,%d\n",getpid(),getppid());
}
else
{
printf("father:%d,%d\n",getpid(),getppid());
}
printf("hehehhe%d,%d\n",getpid(),getppid());//在进程中代码是共用的
return 0;
}
再次查看打印结果:
很明显 printf(“hehehhe%d,%d\n”,getpid(),getppid());是子进程和父进程共享的,因此会打印两次。再次打印出1也是因为父进程没有等待子进程。
而且多次执行这些程序我们可以发现一点bash进程的pid 编号始终是不变的,因此shell的子进程的父进程的Pid一直是7355