一、进程的概念
进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。程序是指令、数据及其组织形式的描述,进程是程序的实体。
二、进程的创建
fork函数
#include <unistd.h>
pid_t fork(void);
返回值:在子进程中为0,在父进程中为子进程ID,若出错为-1
fork函数的工作:
fork函数复制当前进程,在内核进程表中创建一个新的进程表项。
新的进程表项有很多属性和原进程相同:比如堆指针,栈指针和标记寄存器的值。
新的进程表项属性与原进程不同:该进程的PPID被设置成原进程的PID,信号位图被清除(原进程设置的信号处理函数对现进程无效)。
创建子进程后,父进程中打开的文件描述符默认在子进程中也是打开的,且文件描述符的引用计数加1
调用fork一次返回两次,在调用进程(称为父进程)中返回一次,返回值是新派生的进程(子进程)ID号;在子进程中又返回一次,返回值为0。
#include <stdio.h>
#include <unistd.h>
int main()
{
pid_t pid;
pid = fork();
if(pid == 0)
{
printf("This is child.\t");
printf("My parent ID : %d\t",getppid());
printf("PID = %d\n",getpid());
sleep(1);
}
else
{
printf("This is parent.\t");
printf("My parent ID : %d\t",getppid());
printf("PID = %d\n",getpid());
sleep(1);
}
return 0;
}
运行结果为:
在代码里加上sleep(1)是因为有可能会出现一种情况就是其中一个进程进行完了,已经结束运行了另外一个进程还在运行,虽然还是能运行,但是可能会出现命令行已经出现了之后又输出一句输出语句。
fork的内存复制机制:
子进程复制父进程的数据空间(数据段)、栈和堆、父,子进程共享正文段。 也就是说,对于程序中的数据,子进程要复制一份,但是对于指令,子进程并不复制而是和父进程共享。
fork的写时复制:
在子进程创建完成时,子进程和父进程共享内存。但是一旦共享的内存区域要被写入时(不管是子进程要写还是父进程要写)这块区域就会从父进程的进程空间复制到子进程,然后再执行写入,但是原来的内存区域还是被保护的没有被改变,这就是通常说的写时复制,目的是为了节省不必要的内存消耗。