操作系统实验(3)
- 格式:doc
- 大小:104.50 KB
- 文档页数:7
操作系统实验
1
实验三 进程管理--进程的创建与并发执行
一.目的和要求
通过进程的创建、运行和撤销加深对进程概念和进程并发执行的理解,明确进程与程序之间的
区别。
二.实验内容
1、 Shell下的进程控制:用ps命令查看进程;用kill命令中止某些进程;用pstree命令显示系统
中进程的层次结构。(可通过“帮助”查看上述命令有哪些参数)
2、 掌握系统调用fork( ),exec系列函数(6个),exit( ),wait( ),waitpid( ),getpid( ),getppid( )
的功能和实现过程。
3、 编写一段程序,使用系统调用fork( )创建两个子进程。当此程序运行时,在系统中有一个父进
程和两个子进程活动。让每一个进程在屏幕上显示一个字符:父进程显示字符‘a’;两个子进
程分别显示字符‘b’和‘c’。观察屏幕上的显示结果,并分析原因。
4、 将上述的输出字符改为输出较长的字符串,观察进程并发执行,分析执行结果。
5、 编写一段程序,使用系统调用fork( )创建一个子进程,在子进程中显示该子进程及其父进程的
PID,然后子进程睡眠10秒钟(使用系统调用sleep(10));父进程通过调用wait( )等待子进程
结束,并显示该子进程的PID。
6、 编写一段程序,使用系统调用fork( )创建一个子进程。子进程通过系统调用exec系列函数调
用命令ls,调用exit( )结束。而父进程则调用waitpid( )等待子进程结束,并在子进程结束后显
示子进程的标识符,然后正常结束。
三.实验提示
1、fork( )
fork( )是Linux的系统调用,其作用是创建进程,创建的子进程共享父进程在内存的程序段副本。
int fork(void)
创建一个新进程。调用fork的进程称为父进程,新进程是子进程。fork系统调用为父子进程返
回不同的值:子进程中返回0,父进程中返回子进程的PID,即fork( )被调用了一次,但返回了两次,
子进程继承了父进程的许多特性,并具有与父进程完全相同的用户级上下文,父子进程并发执行;
如创建不成功则返回负数值。fork出错可能有两种原因(errno的含义请见后面第6部分):
(1)当前的进程数已经达到了系统规定的上限,这时errno的值被设置为EAGAIN。
(2)系统内存不足,这时errno的值被设置为ENOMEM。
例如下面的代码:
#include
#include
#include
main(void)
{
pid_t pid; /*定义进程ID,pid_t是一种数据类型,在头文件sys/types.h中定义*/
pid=fork();
if(pid<0)
{
printf("fork error\n");
exit(0);
}
else if(pid==0)
printf("this is the child process!\n"); /*子进程执行的代码*/
else
操作系统实验
2
printf("this is the parent process!\n"); /*父进程执行的代码*/
}
虽然父进程与子进程程序完全相同,但每个进程都有自己的程序计数器PC(注意子程序的PC
开始位置),然后根据pid变量保存的fork( )返回值的不同,执行了不同的分支语句,如下图所示:
2、exec系列
exec系统调用用新程序覆盖调用它的进程的地址空间。exec把一个新的程序装入调用进程的内
存空间,来改变调用进程的执行代码。此时,系统把代码段替换成新程序的代码,废弃原有的数据
段和堆栈段,并为新程序分配新的数据段和堆栈段,唯一留下的就是进程号。对系统而言,还是同
一个进程,只不过运行另一个可执行程序。所以,fork( )/exec( )组合是典型的Linux新进程产生模式,
通常先用fork( )创建新进程,然后新进程通过调用exec( )系列执行自己的任务。
exec加后缀,可有多种格式:
int execl(const char *path,const char *arg0,const char *arg1,…,(const char *)0);
int execlp(const char *file,const char *arg0,const char *arg1,…,(const char *)0);
int execle(const char *path, const char *arg0, const char *arg1, ... ,(const char *)0, char *const
envp[]);
int execv(const char *path,const char *argv[]);
int execvp(const char *file,const char *argv[]);
int execve(const char *path, const char * argv[], char * const envp[]);
其中系统调用名称中的l代表长格式,v代表利用argv传参,e代表从envp传递环境变量,p代表从
PATH指定路径搜索文件。
使用以上函数需包含头文件unistd.h。(#include
以上六个函数中,execve是系统调用函数,其它5个函数都是在用户空间中实现的,实际最终
也是调用execve实现最终功能。共同特点:运行成功时没有返回,因为把原来的程序置换了;运行
失败时返回-1,失败原因存于errno 中。
pid=fork();
if(pid<0)
{ printf("fork error\n");
exit(0);
}
else if(pid==0)
printf("this is the child process!\n");
else
printf("this is the parent process!\n");
pid=fork(); if(pid<0) { printf("fork error\n"); exit(0); } else if(pid==0) printf("this is the child process!\n"); else printf("this is the parent process!\n"); pid=fork();
if(pid<0)
{ printf("fork error\n");
exit(0);
}
else if(pid==0)
printf("this is the child process!\n");
else
printf("this is the parent process!\n");
fork( )调用前
fork( )调用后
PC
PC PC
操作系统实验
3
例子:
(1)int execl(const char *path,const char *arg0,const char *arg1,…,(const char *)0);
execl( )用来执行参数path字符串所代表的文件路径,接下来的参数代表执行该文件时传递过去
的argv[0]、argv[1]……,最后一个参数必须用空指针(NULL)做结束。程序范例如下(execl_test.c):
#include
main()
{
execl(“/bin/ls”,”ls”,”-al”,”/etc/passwd”,(char * )0);
}
执行结果: /*执行/bin/ls -al /etc/passwd */
-rw-r--r-- 1 root root 705 Sep 3 13 :52 /etc/passwd
(2)int execlp(const char *file,const char *arg0,const char *arg1,…,(const char *)0);
execlp( )从PATH 环境变量所指的目录中查找符合参数file的文件名,找到后便执行该文件,
然后将第二个以后的参数当做该文件的argv[0]、argv[1]……,最后一个参数必须用空指针(NULL)
做结束。程序范例如下(execlp_test.c):
#include
main()
{
execlp(“ls”,”ls”,”-al”,”/etc/passwd”,(char *)0);
}
执行结果:/*执行ls -al /etc/passwd execlp( )会依PATH 变量中的/bin找到/bin/ls */
-rw-r--r-- 1 root root 705 Sep 3 13 :52 /etc/passwd
(3)int execle(const char *path, const char *arg0, const char *arg1, ... ,(const char *)0, char
*const envp[]);
execle()用来执行参数path字符串所代表的文件路径,接下来的参数代表执行该文件时传递过
去的argv[0]、argv[1]……,最后一个参数必须用空指针(NULL)做结束。与execl()不同的是:execl()
把默认的环境变量不做任何修改地传给被执行的应用程序,而execle()会用指定的环境变量envp去
替代默认的环境变量。程序范例如下(execle_test.c):(注意:程序中的命令“env”作用是“显示当
前用户的环境变量”。)
#include
main()
{
char *newenv[]={“PATH=/bin:/usr/bin”,”HOME=/home/user”,NULL};
execle(“/usr/bin/env”,”/usr/bin/env”,(char *)0,newenv);
}
执行结果:
PATH=/bin:/usr/bin
HOME=/home/user
(4)int execv(const char *path,const char *argv[]);
execv( )用来执行参数path字符串所代表的文件路径,与execl()不同的地方在于execv( )只需两
个参数,第二个参数利用数组指针来传递给执行文件。程序范例如下(execv_test.c):
#include
main()
{
char *argv[ ]={“ls”,”-al”,”/etc/passwd”,(char*)0};
execv(”/bin/ls”,argv);