2021SC@SDUSC
项目环境:- 树莓派4b
- Ubuntu Desktop 21.04
在Linux 系统中,父进程通过调用fork函数创建一个新的运行的子进程。
#include#include pid_t fork(void);
关于fork函数,有如下特性:
子进程得到与父进程用户级虚拟地址空间相同的(但是独立的)一份副本,包括代码和数据段、堆、共享库以及用户栈。子进程还获得与父进程任何打开文件描述符相同的副本,这就意味着当父进程调用fork时,子进程可以读写父进程中打开的任何文件。父进程和新创建的子进程之间最大的区别在于它们有不同的PID。
—— 《深入理解计算机系统》
下面列出测试文件processTest.c的代码:
#include#include #include int main() { pid_t pid; int i = 100; pid = fork(); if(pid == -1) { printf("Creat fork error!!!n"); exit(1); } else if(pid) { i++; printf("The father i = %d.n",i); printf("The father return %d.n",pid); printf("The father pid is %d.n",getpid()); printf("The father ppid is %d.n",getppid()); while(1); //避免进程退出 } else { i++; printf("nThe child i = %d.n",i); printf("The child return %d.n",pid); printf("The child pid is %d.n",getpid()); printf("The child ppid is %d.n",getppid()); while(1); //避免进程退出 } return 0; }
根据以上代码后,我们使用如下命令生成可执行文件:
gcc processTest.c o processTest
在Ubuntu Desktop下运行结果如图:
为什么会产生这种结果呢?在CSAPP中,已经给出了解答:
- 调用一次,返回两次。fork函数被父进程调用一次,但是却返回两次——一次是返回到父进程,一次是返回到新创建的子进程。
- 并发执行。父进程和子进程是并发运行的独立进程。内核能够以任意方式交替执行
它们的逻辑控制流中的指令。- 相同但是独立的地址空间。两个进程的地址空间都是相同的。每个进程有相同的
用户栈、相同的本地变量值、相同的堆、相同的全局变量值,以及相同的代码。- 共享文件。父进程和子进程都把它们的输出显示在屏幕上。原因是子进程继承了父进程所有的打开文件。当父进程调用fork时,stdout文件是打开的,并指向屏幕。子进程继承了这个文件,因此它的输出也是指向屏幕的。
——《深入理解计算机系统》
这就不难理解为什么会产生如图的输出结果。
2. 进程软中断通信Linux中的信号一个正实数,它定义在系统头文件
下面列出测试代码:
#include#include #include #include #include #include int wait_mark; void stop(){ wait_mark = 0; } void waiting(){ while(wait_mark == 1); } int main(){ int p1, p2; while((p1 = fork()) == -1); if(p1 == 0){ wait_mark = 1; signal(SIGINT, SIG_IGN); signal(16, stop); waiting(); printf("nchild process p1 is killed by parent!n"); sleep(3); exit(0); }else{ while((p2 = fork()) == -1); if(p2 == 0){ wait_mark = 1; signal(SIGINT, SIG_IGN); signal(17, stop); waiting(); printf("nchild process p2 is killed by parent!n"); sleep(3); exit(0); }else{ wait_mark = 1; signal(SIGINT, stop); waiting(); kill(p1, 16); kill(p2, 17); wait(0); wait(0); printf("nparent process is killed !n"); exit(0); } } }
运行结果如下:
在本实验当中,创建 2 个进程,通过系统调用 signal() 捕捉键盘上的中断信号。捕捉到中断信号后,父进程用系统调用 kill() 向两个子进程发出信号,子进程捕捉到信号后分别输出信息后终止 。可以看到,我们让子进程 1 接受父进程软中断信号 17 然后转向 stop() 函数,而如果 等待标记不为 0 那么就一直等待父进程的信号 ,其中非常重要的一部就是 signal(SIGINT, SIG_IGN) ,它实现了屏蔽 ctrl+c 的键盘中断信号。



