在Linux中fork函数是创建一个子进程,并且fork函数有两个返回值,并且父进程和子进程的代码共享,但是数据是私有的,各自开辟一份空间来保存数据。如下程序可以看到在fork函数前只是执行了一遍printf函数,而当fork完成了子进程的创建时,父进程和子进程都会执行printf函数。
#include<stdio.h>
2 #include<unistd.h>
3
4 int main()
5 {
6
7 printf("I am Parent pid: %d,ppid: %d\n",getpid(), getppid());
8 sleep(1);
9 pid_t ret=fork();
10 sleep(1);
11 if(ret>0)
12 {
13
14 // while(1)
15 {
16
17 printf("I am Parent pid: %d,ppid: %d\n",getpid(), getppid());
18 sleep(1);
19 }
20
21 }
22 else if(ret==0)
23 {
24 // while(1)
25 {
26
27 printf("I am Child pid: %d,ppid: %d\n",getpid(), getppid());
28 sleep(2);
29 }
30 }
31 else
32 {
33 printf("创建进程失败\n");
34 }
35
36
37 return 0;
38 }
`1、
1、基于以上现象,那么怎样理解进程的创建呢?
所谓的进程的创建是指在操作系统在内存中增加了一个PCB(进程控制块),用来描述进程的信息,以及一组数据和代码。
2、并且fork函数为什么会有两个返回值?
是因为在fork函数中是由一些创建进程的语句和最后的return pid 返回进程的标识符组成,当在return语句前其实已完成了子进程的创建,并且父进程和子进程的PCB都进入了CPU运行队列中了,等待CPU的调度执行。如下图所示,由于子进程和父进程共享相同的代码,但是数据是私有的这体现了进程的独立性,所以可以得出:由于return是语句所以父进程和子进程都要执行,而pid是返回的数据因此父子进程的数据是不一样的,所以fork函数才会有两个返回值。
3、进程的几种状态:
(1)R运行状态(running) : 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里
(2)S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))
(3)D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。
(4)T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
(5)X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。
(6)僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵死(尸)进程,简单的来说就是说父进程还在执行,而子进程已近运行完毕,这时子进程变成了僵尸状态,要等着父进程检测子进程运行完的时候的结果情况,是否正常,是否异常,以及发生了什么异常,而僵尸进程的最明显的特征是,控制子进程的PCB还没有销毁,其内部保持了子进程运行进程的基本信息,方便父进程的读取,获得进程的退出原因。知道这些完成后子进程才会由僵尸进程变为X状态。
(7)孤儿进程:父进程先退出,子进程就称之为“孤儿进程“,而产生的孤儿进程会被我们操作系统中的1号进程进行领养,最后由system中进行回收