一、实验目的
通过进程的创建、撤销和运行加深对进程概念和进程并发执行的理解,明确进程和程序之间的区别。
二、实验内容和步骤
(1)任务一:进程的创建
任务要求:编写一段程序,使用系统调用 fork()创建一个子进程。当此程序运行时,在系统中有一个父进程和一个子进程活动。让每一个进程在屏幕上分别显示字符:父进程显示字符“b”;子进程显示字符“a”,另外父子进程都显示字符“c”。
步骤 1:使用 vi 或 gedit 新建一个 fork_demo.c 程序,然后拷贝清单 2-1 中的程序,使用 cc 或者gcc 编译成可执行文件 fork_demo。例如,可以使用 gcc –o fork_demo fork_demo.c 完成编译。
步骤 2:在命令行输入./fork_demo 运行该程序。
步骤 3:多次运行程序,观察屏幕上的显示结果,并分析多次运行为什么会出现不同的结果。
(2)任务二:子进程执行新任务
任务要求:编写一段程序,使用系统调用 fork()创建一个子进程。子进程通过系统调用 exec更换自己原有的执行代码,转去执行 Linux 命令/bin/ls (显示当前目录的列表),然后调用 exit()函数结束。父进程则调用 waitpid()等待子进程结束,并在子进程结束后显示子进程的标识符,然后正常结束。程序执行过程如图 2-1 所示。
步骤 1:使用 vi 或 gedit 新建一个 exec_demo.c 程序,然后拷贝清单 2-2 中的程序(该程序的执
行如图 2-1 所示),使用 cc 或者 gcc 编译成可执行文件 exec_demo。例如,可以使用 gcc –o exec_demo
exec_demo.c 完成编译。
步骤 2:在命令行输入./exec_demo 运行该程序。
步骤 3:观察该程序在屏幕上的显示结果,并分析。
三、参考程序清单
清单 2-1 创建进程
#include <stdio.h>
#include <stdlib.h>
main()
{
int x;
srand((unsigned)time(NULL));
while((x=fork())==-1);
if (x==0)
{
sleep(rand() % 2);
printf("a");
}
else
{
sleep(rand() % 3);
printf("b");
}
printf("c");
}
清单 2-2 子进程执行新任务
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
pid_t pid;
/* fork a child process */
pid = fork();
if (pid < 0)
{ /* error occurred */
fprintf(stderr, "Fork Failed");
return 1;
}
else if (pid == 0)
{ /* 子进程 */
execlp("/bin/ls","ls",NULL);
}
else { /* 父进程 */
/* 父进程将一直等待,直到子进程运行完毕*/
wait(NULL);
printf("Child Complete");
}
return 0;
}
四、实验流程
(1) exec_demo.c 程序的执行过程
(2)进程的创建
五、实验结果与分析
1.进程的创建,实验结果:
结果分析:主进程输出bc,子进程输出ac,因为主进程和子进程的返回值不同。
2.子进程执行新任务,实验结果:
结果分析:对于父进程,fork()返回子进程的 pid, 对于子进程, fork()返回 0。出错时返回-1。pid = fork();创建子进程,并且接受返回值。如果pid<0,那么为-1出错。否则如果是子进程调用执行函数,如果是父进程则进入等待子进程,子进程运行完毕则运行父进程。
五、小结与心得体会
通过本实验,我对进程的创建、撤销和运行以及对进程概念和进程并发执行有了更深的理解,明确了进程和程序之间的区别。 进程是程序的一次运行活动,属于一种动态的概念 。