为什么要创建进程,首先每个程序的运行都需要一个进程;多进程实现宏观上的并行。
fork的原理,是进程的分裂生长模式。如果操作系统需要一个新的进程,那么就会以cp的方法得到一个新的进程,此时老的进程是父进程,新的进程为子进程。
pid_t fork(void),fork被调用一次会返回两次,返回0为子进程,大于0为父进程。
int main()
{
printf("a.out\n");
pid_t p1=-1;
p1=fork();
if(0==p1)
{
printf("son ");
}
if(0<p1)
{
printf("father ");
}
printf("pid=%d\n",getpid());
}
如果p1<0 fork则会错误
两个printf分别是父进程于子进程的,但是父进程不一定在子进程之前执行。
所以在运行时候要用if去判断谁是父进程,谁是子进程,子进程与父进程的分道扬镳之处就在fork()之后的部分。在父进程中,当if(p1>0)中的p1值为返回子进程的PID,父进程中fork返回值为子进程的PID,子进程中fork的返回值为0,父进程中PID返回值为子进程的ID,子进程使用getppid()得到父进程的ID。
若父进程消亡,则getppid()返回用户的init进程,原因就是父进程消亡会上交进程号给init进程(user)。
一但fork成功,则子进程与父进程将独立运行,有各自的PCB,父进程与子进程在内核中等待调度的机会。
父进程对文件的操作问题:①子进程中会继承父进程打开的文件。正常情况下,父进程打开一个文件,fork创建子进程后,父子进程对文件的write是接续的,因为,lseek是关联的,像O_APPEND,但有时又只会有父子进程中的其中之一的内容,原因是父进程或子进程其中一个关闭文件过快,其中一个还没写完,就找不到入口了为了避免这一情况的发送,就可用通过信号或sleep函数实现延时关闭。
②父进程都去打开文件,正常情况下,分别写各自的文件表,有各自的lseek可以用O_APPEND实现关联,否则你写你的我写我的谁最后写就留下谁的文件。
父进程在fork前干的事情是会影响到子进程的,只有在if的部分才是独立的,本质上希望子进程去干自己的活,不是两方干一模一样的活,还不如复制粘贴。
进程消亡:①进程在运行过程中,占用看内存和IO,进程终止时才会完全释放这些资源。僵尸进程是指子进程先于父进程,每个进程在推出时,操作系统会回收资源,如当malloc没free,open没close都会在进程结束时候回收,但财政系统只回收了运行时消耗的内存与IO,没回收task_struct和栈内存。自身的8kb内存是无法自己回收的,使用要个收尸的,这个进程就是父进程,子进程结束父进程还没结束,这段时间就是僵尸进程。
②父进程调用wait()或waitpid()以显示的方式去收尸。
③父进程结束时,会在不调用wait/waitpid的情况下进行子进程的收尸操作,本质上是为了防止父进程忘记显示调用,防止内存泄漏。
孤儿进程,父进程先于子进程消亡,Linux、将所有孤儿进程归于进程1的子进程。