一、进程相关的基本概念:
1、进程概念:
进程是系统分配资源的基本单位。
- 一个正在运行的程序。
- 一个正在计算机上执行的程序实例。
- 能分配给处理器并由处理器执行的实例。
简言之,进程就是一个正在运行的程序。换句话也就是,每个运行着的程序实例就构成一个进程。
2、pid: 进程id;唯一标识一个进程。
3、pcb: 进程控制块/ 进程描述符;描述一个进程的属性信息的结构体。
4、进程状态:
- 一般情况下,我们会将进程分为:就绪、执行、阻塞,三种状态。
- 为了更加准确的描述进程的状态,我们构建出五状态模型。
- 有挂起态的进程状态转换图。
这种状态是为了,解决处理器长时间等待I/O的现象,充分使用cpu,让处理器处于忙碌状态。我们用/*交换的方法,即当内存中不存在就绪态的进程时,操作系统就把被阻塞的进程换出到磁盘中的挂起队列,重新在挂起队列中调入一个已经就绪的进程。
5、并发和并行:
并发强调的是时间片的轮换,交替执行。
并行则是真实的同时运行,只能用于多cpu(多核)环境。
二、fork()创建进程
一般而言,每个进程都是由另一个我们称之为父进程的进程启动的,被父进程启动的进程叫做子进程。Linux系统启动时,运行一个名为 init 的进程,它是系统的第一个进程,进程号为1,可以将它看作系统的进程管理器;它是所有进程的祖先进程,是因为其他系统进程要么是由 init 进程启动,要么是被 init 进程启动的其他进程启动的。
Linux下创建新进程的系统调用是fork。
其定义如下:
- fork()函数执行后,会产生一个新的进程,新进程会继承原来进程的数据、程序计数器等。
- fork函数调用一次,返回两次。
- fork()执行后,在父进程中返回子进程的pid(不可能为0),在子进程中返回0。
- fork出错时返回值为-1,并设置为errno。
- 子进程复制父进程的数据采用的是写时拷贝,只有在任一进程(父或子)对数据执行了写操作时,才会发生缺页中断,然后操作系统为子进程分配内存并复制父进程的数据。
- 创建子进程后,父进程打开的文件描述符默认在子进程中也是打开的,且文件描述符引用计数加1。
示例:
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <string.h>
# include <assert.h>
int main()
{
char *s = NULL;
int n = 0;
pid_t pid = fork();//创建子进程
assert(pid != -1);
if(pid == 0)
{
s = "child";
n = 4;
}
else
{
s = "parent";
n = 7;
}
int i = 0;
for(;i < n;i++)
{
printf("%d ,s=%s\n",n,s);
}
exit(0);
}