进程概念:
程序:是指编译好的二进制文件, 在磁盘上不占用系统资源(Cpu、内存、打开的文件、设备、锁…)
进程:是一个抽象的概念,与课作系统原里联系紧密。进程是活跃的程序,占用系统资源。在内存中执行。(程序运行起来,产生一个进程)。
程序一剧本(纸)
进程-戏(舞台、演员、灯光)
同一个剧本可以在多个舞台同时上演。同样,同一个程序也可以加载为不同的进程(彼此之间互不影响)。
简单来说进程就是正在执行的程序,是现代分时操作系统的工作单元。
进程是执行的程序,这是一种非正式的说法。进程不只是程序代码(文本段或代码段),通常还包含以下内容:
- 当前活动,如程序计数器的值和处理器寄存器的内容等。
- 进程堆栈(包括临时数据,如函数参数、返回地址和局部变量)和数据段(包括全局变量)。
- 堆,这是在进程运行时动态分配的内存。
并发:简单来说,就是进程同时进行。
串行:简单来说,就是多个进程轮流循环进行。
需要注意几点:
1、虚拟空间的实际使用量会经过MMU处理成相同大小的物理空间。
2、站在CPU角度上看,程序是在虚拟内存上运行。
进程的两种模型
三态模型:
五态模型:
fork函数
fork函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。
进程创建后,系统给新创建的子进程分配资源。我们可以通过进程号pid 来区分父进程和子进程。父进程返回的是子进程的pid,子进程返回的是0。
pid_t pid = fork(); 创建一个子进程
牢记四个函数
getpid():获取当前子进程号;
getppid():获取父进程号;
getuid():获取当前进程用户id号;
getuiid():获取当前进程组id号
连续两次fork语句,进程裂变效果:
进程共享
父子进程之间在fork后。有哪些相同,那些相异之处呢?。
相同处:全局变量、 data、text、栈、堆、环境变量、用户1D、 宿主目录、进程工作目录...
不同处:1、进程ID 2、fork 返回值 3、父进程D4、进程运行时间 5、闹钟(定时器)6、未决信号集。
都要将父进程的0-3G地址空间完全拷贝一份,然后在映射至物理内存吗?
当然不是!父子进程间遵循读时共享写时复制的原则。这样设计,无论子进程执行父进程的逻辑还是执行自己的逻辑都能节省内存开销。
练习一、父进程和子进程共享全局变量
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int n = 100;
int main()
{
int i;
for(i=1;i<=5;i++)
printf("进程开始执行,打印数字%d\n",i);
pid_t pid=fork();
if(pid == -1)
perror("进程创建失败");
else if(pid == 0)
{
printf("我是子进程,打印数字666\n");
printf("child pid=%d,parent pid=%d\n",getpid(),getppid());
printf("uid=%d,gid=%d\n",getuid(),getgid());
n += 100;
printf("%d\n",n);
}
else
{
printf("我是父进程,打印数字888\n");
printf("my pid=%d,parent pid=%d\n",getpid(),getppid());
printf("uid=%d,gid=%d\n",getuid(),getgid());
n += 100;
printf("%d\n",n);
}
sleep(5);
printf("公共代码部分:子进程+父进程测试...\n");
printf("%d\n",n);
return 0;
}
孤儿进程和僵尸进程
孤儿进程:父进程先于子进程结束,则子进程就成为一个孤儿进程
僵尸进程:进程终止,父进程尚未回收,子进程残留资源存放于内核中,成为僵尸进程(子进程结束,父进程尚未结束)
注意一下几点:
1、使用命令 ps ajx 查看进程信息,包括父子进程关系
2、使用kill -9 +pid进程号强制杀死进程
3、孤儿进程一旦形成,无法强制退出,必须杀死其进程号才可结束
4、僵尸进程一旦形成,必须杀死其父进程才可结束
练习二、编写一个孤儿进程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
pid_t pid=fork();
if(-1 == pid)
{
perror("进程操作错误");
exit(1);
}
else if(0 == pid)
{
printf("子进程创建成功\n");
while(1)
{
printf("pid=%d,ppid=%d\n",getpid(),getppid());
printf("uid=%d,gid=%d\n",getuid(),getgid());
sleep(2);
}
}
else
{
printf("父进程创建成功\n");
printf("pid=%d,ppid=%d\n",getpid(),getppid());
printf("uid=%d,gid=%d\n",getuid(),getgid());
sleep(2);
}
return 0;
}
练习三、编写一个僵尸进程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
pid_t pid=fork();
if(-1 == pid)
{
perror("进程操作错误");
exit(1);
}
else if(0 == pid)
{
printf("子进程创建成功\n");
printf("pid=%d,ppid=%d\n",getpid(),getppid());
printf("uid=%d,gid=%d\n",getuid(),getgid());
sleep(1);
}
else
{
printf("父进程创建成功\n");
while(1)
{
printf("pid=%d,ppid=%d\n",getpid(),getppid());
printf("uid=%d,gid=%d\n",getuid(),getgid());
sleep(2);
}
}
return 0;
}