1.获取进程id的方法
pid_t getpid(); 获得当前调用该方法的进程id号(无参)
pid_t getppid(); 获得当前调用该方法的父进程进程id号(无参)
注意:每个进程都有其父进程!
进程号为2346的为父进程的父进程,为命令解释器bash(当前最好用的命令解释器),用户通过命令解释器bash和系统(内核)交互。具体操作:bash在执行可执行程序./main2时,会将自己fork()复制一份-> 子bash,再将子bash替换为可执行程序main2后再运行。
终端中执行的任何命令:其父进程均为bash。
2.对于在父进程中fork()之前定义的变量n,其在父进程、子进程中地址(逻辑地址)相同,但值不同。
解释:打印出的n的地址(%p)为逻辑地址!!!对于逻辑地址,父进程与复制得来的子进程相同,而物理地址不相同!若是一个进程中,逻辑地址相同则物理地址相同,但现在为两个进程(无可比性),其真实的物理地址在不同空间。
3.fork()示例1 问:打印了多少个A? 3个。
复制后的子进程从fork()返回值带回后处执行。
4.fork()示例2 问:打印了多少个A? 6个。
附加:若变为printf("A"); 去掉 n 一定会输出>6个A且为偶数个。由于输出的A会先放在缓冲区,父进程fork()复制产生子进程时是连同缓冲区(内存)一起复制的,故会将未输出的A一同复制,到结束进程时刷缓冲区一并输出。
5.总结以上:(1)fork()复制进程:父进程中fork()的返回值为子进程id号。子进程中fork()返回值为0!
(2)程序中使用的地址为逻辑地址!
(3)父进程的内存也会通过fork()复制产生子进程时复制给子进程。
二、僵死进程1. 当父进程比子进程结束早时,还未结束的子进程叫做孤儿进程。按照约定所有没父进程的子进程都需要被某个特定的进程(之前主要是init pid=1的进程收养,现在很多系统规定不再是1号进程,如下图为id号=1353的进程收养孤儿进程)收养。
2. 进程结束
(1)过程
PCB会被串成一个双向链表,当子进程结束(exit(0) //退出码为0)时,需要释放掉为其开辟的内存空间,同时其PCB需要被删除。但在这之前,子进程的PCB会接受其返回的退出码0,此时父进程要通过获取子进程返回的退出码来了解子进程的状态即是否正常结束(0代表成功)。故子进程的PCB需要保留到父进程结束后才可以删。若父进程先结束,init 进程收养子进程,则子进程就要把其退出码返回给该进程。
总结:
(1)父进程先结束,子进程变为孤儿进程,被特定进程(init pid==1)收养。
(2)当子进程先结束,父进程没有获取子进程的退出码时,子进程变为僵死进程
(2)父进程通过调用 wait() 获取退出码,传入任意整型值的地址,将其修改为退出码。
WIFEXITED():获取子进程退出状态
WEXITSTATUS():获取子进程退出码
起初父进程未被打印,由于wait()处阻塞,父进程需要等待子进程结束获取退出码。



